介绍
JEIOptimizer
并行构建 JEI 的搜索索引——大型整合包的服务器加入时间最多可缩短 17 秒。
缘起
我和朋友在一台私人的 AllTheMods 服务器上玩。每次断线、重启,或是说一句“我去拿点零食”,都意味着要盯着 “正在加入世界…” 发呆 40 秒,而其他人早就开始挖矿了。
我受够了。于是花了一个周末研究 JEI 的源代码,而不是玩游戏。这个模组就是这么做出来的。
功能介绍
连接到模组服务器时,JEI 会从头重建整个物品搜索索引——因为服务器可能会带有自定义配方。在一个包含 250 个模组、约 50,000 种物品的整合包中,这会让主线程耗时 12 秒以上。客户端只能卡在那里不动。
JEIOptimizer 会改用工作线程来构建索引。每个搜索前缀(物品名称、模组 ID、标签等)都拥有独立的数据结构,因此可以同时构建——不会互相争用,也不会发生竞争条件。
实际测试数据
测试环境:250 多个模组的整合包(AE2、通用机械、机械动力、Cobblemon、Apotheosis、AllTheCompressed 等)。Ryzen 5600X · 10 个工作线程 · NVMe · 分配 8 GB 内存 · 远程服务器(Hetzner 数据中心)。
| 阶段 | 原版 JEI | + JEIOptimizer | 耗时缩短 |
|---|---|---|---|
| 构建成分过滤器 | 12.00 s | 0.79 s | −94%(快 15 倍) |
| JEI 启动总耗时 | 25.84 s | 14.17 s | −45% |
| 总连接时间 | 约 40 s | 约 23 s | −42%(缩短 17 s) |
再加上下面的工具提示优化,连接服务器的时间可以稳定地从 40 s 缩短至约 23 s。
工作原理(技术细节)
JEI 的搜索索引分为多个“前缀”——名称、模组 ID、标签、工具提示、创造模式物品栏、颜色、资源 ID。每个前缀都拥有独立的后缀树,因此可以安全地分别构建。
原版 JEI:由一个线程依次遍历每个前缀的所有成分。
JEIOptimizer:同时构建各个前缀,每个工作线程负责一个前缀。
工具提示前缀会刻意保留在主线程上构建。构建时会调用 ItemStack.getTooltipLines(),这会运行任意模组代码——而许多模组会在这里访问只能由主线程操作的状态。它仍会与工作线程池并行运行,因此不会增加总耗时;同时也不会在不该调用的线程上执行代码。
过滤模式(在配置中设置)
OFF— 原版 JEI 行为BATCH— 小幅提升缓存友好性,仍为单线程PARALLEL_PREFIX— 按前缀并行构建(安全)PARALLEL_FULL— 还会并行处理前缀内的分词(默认模式,速度最快)
配方生成
JEI 会在启动时通过隐藏菜单为每种组合生成若干合成条目——每个可附魔物品 × 每种附魔 × 每个等级各生成一条,此外还会为整合包中的每种可损坏物品生成修复条目。
默认启用(无感优化):以前每次写入一个输入槽都会触发完整的配方重算,而且第一次重算最多只能读取到一半输入。现在会跳过这些冗余重算。生成的条目和数值保持不变,只是减少了不必要的工作。
可选(会改变显示内容):可以完全跳过生成这些条目。对于包含数百种附魔的整合包,这能大幅缩短启动时间,但这些条目也会从 JEI 中消失。此选项默认关闭;无论是否启用,都不会影响实际配方。
[recipes]
skip_redundant_menu_updates = true # 透明,无损失
skip_generated_enchantment_recipes = false
skip_generated_repair_recipes = false
再省 8 秒(手动调整 JEI)
在 config/jei/jei-client.ini 中,将以下内容改为:
tooltipSearchMode = DISABLED
JEI 每次连接时都会为所有物品的提示文本建立索引。一些模组在渲染提示文本时会执行大量计算——白白占用原本 12 秒中的很大一部分。玩家几乎总是按名称搜索,而不是搜索提示文本。
如果仍想通过 $ 前缀搜索提示文本,请改用 REQUIRE_PREFIX。
配置
config/jeioptimizer-client.toml(自动生成):
[filter]
mode = "PARALLEL_FULL" # 默认。安全,速度最快。
worker_count = 0 # 0 = 自动(核心数 - 2)
log_timing = true # 记录耗时以供验证
[plugins]
parallel_phases = [] # 实验性功能——见下文
parallel_creative_tabs = false # 实验性功能——见下文
[recipes]
skip_redundant_menu_updates = true
skip_generated_enchantment_recipes = false
skip_generated_repair_recipes = false
开箱即用的安全默认设置。放入模组文件即可享受加速,无需修改任何配置。
兼容性
- Minecraft:1.19.2 · 1.20.1 · 1.21.1 · 26.1.2 · 26.2
- 模组加载器:Forge(1.19.2、1.20.1)· NeoForge(1.21.1 及更新版本)
- JEI:每个版本都需使用对应的构建版本——请查看文件列表
- 运行端:仅客户端——无需安装到服务器
JEI 经常会在次要版本更新之间更改内部实现,因此每个构建版本都针对特定的 JEI 版本范围。请下载与你的整合包相匹配的文件。
无法加速的部分
坦诚说明适用范围:
- ❌ 游戏启动(模组构建、模型烘焙、资源包重载)
- ❌ 服务器数据同步(配方、标签、注册表)——受网络和模组序列化限制
- ❌ 各模组运行时数据重新生成——Create 每次连接都会生成 2,124 个配方,Cobblemon 会重新同步所有化石、标记和浆果,Apotheosis 会重新加载所有词缀。这些都是模组本身的设计选择。
JEIOptimizer 将 JEI 从性能瓶颈中移除。它不再是最耗时的环节——其他模组仍会照常运行。
实验性功能(默认关闭)
这些功能经过测试,但发现在实际整合包中可能导致问题。可选择启用,但建议仅在模组组合经过谨慎筛选时使用:
plugins.parallel_phases— 并行注册插件配方。许多 JEI 插件(Theurgy、Ars Nouveau、Compact Machines)并非线程安全,可能导致崩溃。plugins.parallel_creative_tabs— 并行构建创造模式物品栏分类。许多模组会以非线程安全的方式缓存分类状态;在我们的测试中,JEI 中有 22% 的物品因此丢失。
除非清楚自己在做什么,否则请保持关闭。
常见问题
问:这会影响 JEI 搜索吗?
默认设置改变的是索引的构建方式,而不是索引的内容。物品、配方和搜索结果都保持不变。
问:我的整合包比较小,效果会不会没那么明显?
会。物品数量少于约 10,000 时,提升有限。本模组专为拥有 30,000 件以上物品的整合包设计。
问:为什么不向 JEI 提交 PR?
也许以后会。JEI 作者 Mezz 一向倾向于谨慎改动,因此他可能不欢迎在核心代码中引入并行处理。这个模组让你无需等待上游更新。
问:需要安装到服务器端吗?
不需要。这是纯客户端的 Mixin。将它放入服务器的 mods/ 文件夹不会产生任何效果。
问:它兼容 EMI / REI 吗?
不兼容,本模组专为 JEI 开发。EMI 有自己的架构(而且本身已经很快)。
鸣谢
已在自定义的 250 多个模组整合包以及 AllTheMods10、AllTheMons 中测试。
感谢 Mezz 保持 JEI 源码开放且易于阅读,让我们得以从外部进行优化。
常见问题
JEIOptimizer 支持哪些 Minecraft 版本?
JEIOptimizer 支持 Minecraft Java 版 1.19.2–26.2,共 5 个版本,可用的加载器:Forge / NeoForge。下载时注意选择和你游戏版本一致的文件。
JEIOptimizer 怎么安装?
先用 PCL2 或 HMCL 启动器安装对应版本的 Forge / NeoForge,再把下载的 .jar 文件放进游戏目录的 mods 文件夹,重新启动游戏即可。开启了版本隔离的,mods 文件夹在 versions/版本名 下面。
big_energy 的其他作品
查看全部 →Glassential Renewed
各种类型的玻璃,助你建造。已更新至新版MC。
Decorative Blocks Reborn
新增了一些可用于建造的方块。已更新至 1.21.1 及更高版本。
Radium Re-Reforged
Radium Reforged 1.20.1 的分支版,专注于修复漏洞。
WorldBorder (dimensional)
按维度管理世界边界,而非按世界管理!(已更新至新版本)
评论
登录后评论和评分