ASMDataTableV2

基本信息

属性 值
类 com.mitchej123.jarjar.fml.common.discovery.ASMDataTableV2
父类 cpw.mods.fml.common.discovery.ASMDataTable
Annotation desc 常量 API_ANNOTATION = "cpw.mods.fml.common.API"
修改点 @API 数据按 apiVersion 倒序、getAnnotationsFor 缓存按 jar 分组

ASMDataTableV2 扩展 FML 原版 ASMDataTable,引入两项关键优化:

  1. API 排序:原版按发现顺序返回 @API 数据;V2 按 apiVersion 倒序排序,让最新版本的 API 拥有者优先被依赖方识别
  2. 按 jar 分组:getAnnotationsFor(ModContainer) 的 O(n) 扫描改为按 jar 缓存的 SetMultimap

@API 排序

@Override
public Set<ASMData> getAll(String annotation) {
    final Set<ASMData> all = super.getAll(annotation);
    if (!API_ANNOTATION.equals(annotation) || all == null || all.size() < 2) return all;
    final List<ASMData> sorted = new ArrayList<>(all);
    sorted.sort(Comparator.comparing(ASMDataTableV2::apiVersionOf).reversed());
    return new LinkedHashSet<>(sorted);
}

private static DefaultArtifactVersion apiVersionOf(ASMData data) {
    String v = null;
    if (data != null && data.getAnnotationInfo() != null) {
        final Object raw = data.getAnnotationInfo().get("apiVersion");
        if (raw instanceof String) v = (String) raw;
    }
    if (v == null || v.isEmpty()) v = "0.0.0";
    return new DefaultArtifactVersion(v);
}

只对 @API 注解做排序(其它注解保留原顺序以保持兼容性),返回 LinkedHashSet 维持迭代次序。

getAnnotationsFor 缓存

@Override
public SetMultimap<String, ASMData> getAnnotationsFor(ModContainer container) {
    if (containerAnnotationData == null) {
        final Map<File, ImmutableSetMultimap.Builder<String, ASMData>> builders = new HashMap<>();
        for (Map.Entry<String, ASMData> e : globalAnnotationData.entries()) {
            final ASMData data = e.getValue();
            final ModCandidate cand = data.getCandidate();
            if (cand == null) continue;
            final File src = cand.getModContainer();
            if (src == null) continue;
            builders.computeIfAbsent(src, k -> ImmutableSetMultimap.builder()).put(e.getKey(), data);
        }
        final Map<File, ImmutableSetMultimap<String, ASMData>> bySource = new HashMap<>(builders.size());
        for (Map.Entry<File, ImmutableSetMultimap.Builder<String, ASMData>> e : builders.entrySet()) {
            bySource.put(e.getKey(), e.getValue().build());
        }
        final ImmutableMap.Builder<ModContainer, SetMultimap<String, ASMData>> out = ImmutableMap.builder();
        for (ModContainer cont : containers) {
            final File src = cont.getSource();
            final ImmutableSetMultimap<String, ASMData> mm = src == null ? null : bySource.get(src);
            out.put(cont, mm == null ? ImmutableSetMultimap.of() : mm);
        }
        containerAnnotationData = out.build();
    }
    return containerAnnotationData.get(container);
}

按 ModContainer.getSource() 分组 global annotation data,每个 ModContainer 只看见来自同一 jar 的注解。懒加载:第一次调用时构造 cache。

替代 globalAnnotationData

V2 构造函数替换 globalAnnotationData 类型为 LinkedHashMultimap:

public ASMDataTableV2() {
    super();
    this.globalAnnotationData = LinkedHashMultimap.create();
}

LinkedHashMultimap 保证插入顺序稳定,对 @API 排序前的初始集合尤为重要。

与原版差异

操作 原版 V2
getAll("@API") 保留发现顺序 按 apiVersion 倒序
getAll(其它) 不变 不变
getAnnotationsFor(container) 遍历整个 globalAnnotationData 过滤 按 jar 文件缓存

相关条目