性能分析器 Profiler
基本信息
| 属性 | 值 |
|---|---|
| 类型 | mod 列表扫描 / 可转换目标发现工具 |
| 实现类 | net.vfyjxf.nechar.utils.Profiler |
| 触发方式 | /nech profile |
| 线程优先级 | Thread.MIN_PRIORITY |
| 产出文件 | logs/necharacters-profiler.txt(Gson 缩进 JSON) |
| 扫描范围 | 游戏目录下的 mods 目录(递归) |
目的
本模组的拼音支持完全依赖"把其他模组界面里的 String.contains / String.matches / Pattern.matcher 换成拼音实现"。默认目标列表只能覆盖已知模组(见 默认转换目标列表),Profiler 就是用来发现尚未收录、但同样调用了这些方法的目标方法的辅助工具——扫描结果可直接作为 AdditionalTransformerStringList / AdditionalTransformerRegExpList 的素材。
执行流程
| 步骤 | 方法 | 行为 |
|---|---|---|
| 1 | run() |
以 new File("mods") 为根目录调用 scanDirectory,结果数组存入 Report.jars |
| 2 | scanDirectory(File) |
listFiles() 遍历:.jar 文件 → ZipFile 打开后 scanJar;子目录 → 递归扫描并把结果并入列表 |
| 3 | scanJar(ZipFile, callback) |
遍历 jar 内条目 |
| 4 | scanClass(InputStream, ...) |
对每个 .class 用 ASM ClassReader 解析,按四类签名收集方法 |
| 5 | 过滤 | 若一个 jar 的四类结果全部为空,则不加入报告(cbkJar.accept(ret) 不执行) |
| 6 | 输出 | NechCommand 把 Report 以 Gson 缩进格式写入 logs/necharacters-profiler.txt |
scanJar 收集的四类签名
每个 .class 条目内按方法遍历指令流,命中下列特征即记录 类名:方法名:方法描述符(/ 已替换为 .)并 break(每个方法只记录首个命中):
| 报告字段 | 指令特征 | 归属转换器 |
|---|---|---|
methodsString |
INVOKEVIRTUAL java/lang/String.contains 描述符 (Ljava/lang/CharSequence;)Z |
TransformerString |
methodsRegExp |
INVOKEVIRTUAL java/lang/String.matches 描述符 (Ljava/lang/String;)Z |
TransformerRegExp |
methodsRegExp |
INVOKEVIRTUAL java/util/regex/Pattern.matcher 描述符 (Ljava/lang/CharSequence;)Ljava/util/regex/Matcher; |
TransformerRegExp |
methodsStrsKt |
INVOKESTATIC kotlin/text/StringsKt.contains 描述符 (Ljava/lang/CharSequence;Ljava/lang/CharSequence;Z)Z |
无对应转换器(仅报告) |
methodsSuffix |
NEW 指令的目标为 net/minecraft/client/util/SuffixArray、cgx 或 cgz |
无对应转换器(仅报告) |
注意 methodsSuffix 的判定条件用括号写法为 NEW && (SuffixArray || cgx) || cgz——按 Java 运算符优先级,cgz 分支不受 NEW 与前两个类的限制。
容错处理
| 情形 | 处理 |
|---|---|
class 文件 entry.getSize() + 4 > Integer.MAX_VALUE |
打印日志 Class file ... is too large, skip. 并跳过该类 |
读取条目 IOException |
打印 Fail to read file ... , skip. 并继续 |
ClassReader.accept 抛异常 |
若 classNode.name 非空则打印 File decoding of class ... failed. Try to continue. 继续;否则包装成 IOException 抛出 |
打开 jar IOException |
e.printStackTrace(),跳过该文件 |
mcmod.info 解析
scanJar 额外识别名为 mcmod.info 的条目并用 Gson 解析进 JarContainer.mods:
- 先尝试解析为
ModContainer[](数组形式); - 捕获异常后回退解析为单个
ModContainer; - 两者都失败则打印
Fail to read mod info in jar file ..., skip.。
每个 ModContainer 字段:modid、name、version、mcversion、url、authorList。
报告结构
| 类 | 字段 |
|---|---|
Report(公开) |
version(占位常量 @VERSION@)、mcversion(MinecraftForge.MC_VERSION)、date(实例初始化块中用 SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH) + GMT 时区生成)、jars(JarContainer[]) |
JarContainer(私有) |
mods(ModContainer[])、methodsString、methodsRegExp、methodsSuffix、methodsStrsKt(均为 String[]) |
ModContainer(私有) |
见上 |
Report 的 date 字段在实例初始化块中计算,因此每次 new Report() 都会重新取当前时间。
相关条目
- /nech 命令 -
profile子命令的触发与输出反馈 - 默认转换目标列表 - 扫描结果的用途与格式要求
- 转换器注册表 -
MethodDecoder的条目格式校验 - TransformerString -
methodsString的对应转换器 - TransformerRegExp -
methodsRegExp的对应转换器