TooManyRecipeViewers

TooManyRecipeViewers

由Nolij编写的用于在EMI中运行JEI插件的兼容层

优化

重要许可声明

以任何形式使用本项目,即表示您对本项目许可条款(见许可)给予“明确同意”,并确认我(本项目作者)已履行许可中“在合理情况下努力获得接收者对许可条款的明确同意”的义务。

TooManyRecipeViewers

TooManyRecipeViewers(简称 TMRV)是一个兼容层,用于在不安装 JEI 的情况下,运行 JEI 插件搭配 EMI。由 Nolij 编写。

使用本模组需要安装 EMI。

为什么使用 TMRV 而不是 EMI+JEI(又称 JEMI)?

JEMI 是 EMI 内置的兼容层,通过大量依赖 JEI 内部实现,使 JEI 插件_基本_能在 EMI 上运行。它设计得尽可能简单,依赖 JEI 先处理配方数据,然后导入 EMI。

TMRV 与 JEMI 不同——它旨在完全替代 JEI API(注意:TMRV 确实包含一些未经修改的 JEI 内部代码——见 JEI 代码复用)。TMRV(在可行的情况下)将 JEI API 替换为 EMI API 的直接映射器,而不是加载整个 JEI 注册表然后事后查询。这有几个优点,包括更有效地利用系统资源,但这也是一种权衡,因为 TMRV 的方法使维护工作比 JEMI 复杂得多。JEMI 是故意这样设计的,让 EMI 的开发可以专注于改进 EMI 本身,我完全支持这种做法。

简而言之:TMRV 比 JEMI 高效得多,但代价是维护起来比 JEMI 费力得多,而且没有人应该期望 EMI 投入这么多精力去支持一个在设计时故意未被参考的 API。要庆幸 EMI 开箱就能加载 JEI 插件——这本身就付出了不少努力。

话虽如此,TMRV 相比 JEMI 有两个主要优势:

1. 插件兼容性

TMRV 对 JEI API 的覆盖比 JEMI 更好(有一个例外——见已知 API 限制)。截至撰写本文时,这包括:

  • 更好地转换内置配方类型(JEMI 仅支持合成和信息配方类型;TMRV 支持所有内置的 JEI 配方类型)
  • 物品/搜索别名支持
  • createRecipeExtras 支持

2. 效率

使用 TMRV,你进入世界总是比 JEMI 更快。这是因为 JEI 插件初始化会阻塞世界加载——在初始化所有 JEI 插件之前,你无法开始游戏。而 EMI 是在世界加载_之后_异步加载插件的。

这意味着即使 TMRV 加载 JEI 插件比 JEI 本身_更慢_(事实并非如此,TMRV 加载速度明显更快——见基准测试),使用 TMRV 的世界加载总是比 JEMI 更快。

如前所述,TMRV 将大部分 JEI API 替换为对应 EMI API 的映射器——这意味着 JEI 内部实现的很大一部分可以完全移除。无需初始化和存储整个 JEI 配方注册表——TMRV 只需将 JEI API 调用转换为 EMI 调用,并将响应转换回 JEI 格式。可以把 TMRV 想象成 Wine 或 Proton,而 JEMI 是虚拟机。JEMI 使用真实的 JEI,因此在某些场景下 TMRV 会出错而 JEMI 不会(注意这不一定意味着 JEMI 真正支持某种场景,只是看起来像支持),但 TMRV 总体上比 JEMI 更高效。

基准测试

完整结果和获取步骤记录在 BENCHMARKS.md 中。这些结果不是挑选出来的。测试步骤完全按照该文件中的文档执行。我鼓励社区进行验证。

加载时间

TMRV JEMI 对比项
Craftoria 1582ms(世界加载前 5ms,世界加载后 1577ms) 11036ms(世界加载前 10000ms,世界加载后 1036ms) -9454ms(世界加载前 -9995ms,世界加载后 +541ms)
ATM10 4951ms(世界加载前 3ms,世界加载后 4948ms) 20132ms(世界加载前 15550ms,世界加载后 4582ms) -15181ms(世界加载前 -15547ms,世界加载后 +366ms)
Finality: Omnia 3010ms(世界加载前 6ms,世界加载后 3004ms) 6354ms(世界加载前 4425ms,世界加载后 1929ms) -3344ms(世界加载前 -4419ms,世界加载后 +1075ms)

内存使用

TMRV JEMI 对比项
Craftoria 4.278 GiB 4.386 GiB -110.6 MiB(约)
ATM10 4.401 GiB 5.273 GiB -892.9 MiB(约)
Finality: Omnia 1.947 GiB 2.065 GiB -120.8 MiB(约)

已知 API 限制

JEI 配置文件

.minecraft/config/jei/blacklist.json 是 TMRV 唯一读取的 JEI 配置文件。该文件对于原版物品类型以及由 JEI 插件添加的模组物品类型应该_可以_正常工作(这不包括原生支持 JEI 和 EMI 的模组,如 Mekanism)。这是为从 JEI 迁移过来的整合包提供的过渡方案。JEMI 也有类似的缺陷。EMI 有自己的隐藏物品配置——请使用该配置。所有其他 JEI 配置文件都被 TMRV 完全忽略,并且没有计划支持它们。

配方管理器插件

JEI API 支持“配方管理器插件”。这些插件允许模组控制自己的配方注册表,并在运行时自行处理配方查找。

TMRV 将尝试从这些插件中提取配方,但这对大多数插件无效,并且绝不是对该功能的适当支持。超出此范围的支持没有计划。配方管理器插件是一个过时的概念,很少有插件仍在使用,并且如果没有非常侵入性的 EMI mixin,就无法正确支持——这是我在这项目中不打算使用的。

运行时注册表更改

JEI API 支持在运行时(即插件注册完成后)修改配方和物品注册表。这个概念与 EMI 不兼容,我也不想支持这种做法。因此,在 IModPlugin.onRuntimeAvailable 被调用后,所有用于运行时注册表修改的 API 在被调用时都会抛出 IllegalStateException,以避免潜在的混淆。

JEI 代码复用

计划在未来更新中替换更多 JEI 内部实现。然而,由于各种原因,JEI 的某些部分根本不值得重新实现。无论如何,TMRV 中已经替换了足够多的 JEI 代码,我可以自信地说:

  1. 使用 mixin 实现与 JEMI 相同的改进是不可行的(至少不能理智地实现),并且
  2. 已经有足够多的 JEI 内部实现被替换或移除,我认为这对 JEI 并不不公平,尤其是考虑到 JEI 的许可证明确允许这样做。

许可

本项目根据 OSL-3.0 许可。更多信息,请参阅 LICENSE。

部分代码复制自 EMI 和 JEI,并遵守其版权许可。本项目中的所有修改均与本项目其他部分使用相同的许可,即 OSL-3.0。