mcpField
P
port-a-mod

port-a-mod

github.com/rehan-remade开发9.2k640 次安装1 天前更新
代码仓库

关于 port-a-mod

port-a-mod 是用于将现有 Mod 忠实移植到其他游戏版本或加载器的编码技能。它将固定的原始版本作为规范,强调提取数据、逐单元实现、许可核查和基于测试证据的验证。

主要功能

  1. 01固定并审查原始版本
  2. 02用矩阵跟踪子系统适配
  3. 03提取注册数据而非手动重录
  4. 04逐单元移植机制并编写测试
  5. 05通过服务端和客户端测试验证
  6. 06记录许可与已知差异

适用场景

  1. 01在不同游戏版本间移植 Mod
  2. 02审查移植内容是否偏离原版
  3. 03规划游戏逻辑和客户端行为测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rehan-remade/universal-modder --skill port-a-mod

安装后在 Claude Code 中输入/port-a-mod确认已加载。

附带文件references/minecraft-1-7-10-forge-to-1-20-fabric.md

详细介绍

忠实移植 Mod

移植现有 Mod 时,原版就是规范。移植很少会因为缺少代码而失败,真正的问题是偏移:

  • 凭记忆或 Wiki 还原数值;
  • 借用同一 Mod 后续重写版本的机制;
  • 悄悄做出“改进”;
  • 渲染效果大致相似;
  • 忘了原版在客户端执行的检查。

下面的方法将 Thaumcraft 4.2.3.5 从 Minecraft 1.7.10 Forge 移植到了 1.20.1 Fabric:

  • 原版的 859 个类变成了约 77,000 行移植代码;
  • 323 个 GameTest 覆盖了它,并通过脚本化的真实客户端场景检查测试无法覆盖的内容;
  • 工作跨越了多个会话,使用了两个 Agent 账户。

实地记录 knowledge/games/minecraft/porting-thaumcraft-4-1-7-10-forge-to-minecraft-1-20-1-fabric.md 记载了其中的注意事项。Minecraft 特定映射见 references/minecraft-1-7-10-forge-to-1-20-fabric.md。

围绕此技能运行 mod-any-game 工作循环(intake、recon、lab、verify、publish、field note)。此技能会将其中的“垂直切片”步骤替换为一系列较长的切片,每个原版单元对应一个切片。将一款游戏的内容或机制引入另一款游戏,属于 mashup-mods 技能,而非此技能。

开始前:许可证

原版的代码和素材归其作者所有。移植基于这些内容构建,通常还会使用它们的反编译版本,因此原版许可证决定了移植版可以发布哪些内容。(这不是法律建议;如有疑问,请咨询作者。)

  • 查找你要移植版本的许可证:Mod 的仓库(LICENSE)、Mod 页面、jar 中的文件或作者的发布帖。将许可证及链接写入状态文档(第 7 节)。
  • 开放许可证(MIT、LGPL、GPL、Creative Commons 许可证):遵循其条款。保留版权声明,注明作者,并在许可证要求时使用相同许可证(GPL、LGPL、CC BY-SA)。
  • **保留所有权利、完全没有许可证,或包含“禁止移植”条款:**发布移植版的任何内容(jar、公开仓库、原版纹理或声音)都需要获得作者或当前权利人的许可。向他们征求许可,并将回复(链接或引文)保存在状态文档中。未经许可,移植版必须保持私有。
    • 此处作为实例的 Thaumcraft 4 是闭源的。2014 年,其作者曾让 GitHub 下架一份反编译副本 (DMCA 通知)。
  • **开始前告知用户属于哪种情况。**是否为自己的整合包制作私有移植版,由用户自行决定。
  • 在移植版及任何发行版本中注明原作者,且不要将移植版说成官方版本。

0. 确定唯一的事实来源

  • 锁定确切版本:jar、其哈希值(SHA-1)、来源和变更日志。对于已停止更新的 Mod 系列,通常应以最后一个版本为准。
  • **只使用一个版本作为参考。**同名的后续重写版本(Thaumcraft 5 和 6 相对于 4,或“Reborn”“Legacy”分支)都是不同的 Mod。
    • Thaumcraft 移植项目一开始选错了基础版本,中途才更换。
    • 数周后,代码中仍然残留着 TC5 网格、纹理、输入处理器和挥击钩子,尽管每次审计都在将游戏玩法与 TC4 对比。
    • 如果基础版本确实要更换,请归档旧状态,将每个部分分类为保留/调整/替换/移除,并搜索注释和标识符,查找旧版本名称。
  • **将规则写在每位后续 Agent 都能看到的地方:**项目的 AGENTS.md(任何特定于 Agent 的说明文件都应指向它)。示例: “ 是唯一的游戏玩法来源。保留其数值、特性和可观察到的 Bug。不要参考后续版本。不要悄悄改进游戏玩法。除非实际运行过,否则绝不要声称构建或测试已通过。”

1. 构建私有参考资料

  • 如果原项目的源代码已发布(其代码仓库、sources jar),请基于固定版本标签中的源代码开展工作,并且只反编译 jar 来确认二者一致。
  • 先使用 Vineflower 反编译。 对于无法处理的类,再改用 CFR,并统计这些类的数量。逆向工程技能中提供了相关工具。
  • 重映射为易读名称:
    • 1.7.10 Forge jar 使用 SRG 名称(func_12345_a、field_1234_b)。使用 MCP stable_12 CSV(methods.csv、fields.csv)重映射;用替换标记的脚本即可。1.12 使用 stable_39。
    • 在目标端,通过 javap 读取加载器缓存中的映射后游戏 jar。它会显示 Mixin 的名称、lambda 名称和局部变量槽位。Loom 的 genSources 会生成易读的源代码。
  • 提取原始资源(纹理、模型、lang、声音),并放在反编译文件旁边,以便资源审计可以与其哈希值进行比对。
  • 保持私有。 反编译内容绝不随项目发布,也绝不提交到公开代码仓库(硬性规定)。
    • 确保未来每个会话都能访问这些内容:使用独立的私有代码仓库,或将其放在移植项目代码仓库之外的固定文件夹中。
    • 不要将其纳入移植项目自身的历史记录。日后公开的代码仓库会发布其全部历史记录。
    • Thaumcraft 移植项目将 reference/ 保存在私有代码仓库中,因此每次开启新的云端会话,都能在更改任何内容之前读取原始项目。

2. 清点内容并制定适配矩阵

  • **列出原项目的每个子系统:**注册表、事件处理器、数据包、GUI 和屏幕、渲染器、世界生成、战利品、配置、命令、公共 API、兼容钩子。
  • **编写矩阵:**针对每个领域,列出原项目类、移植项目类和结论(保留/适配/替换/移除/缺失)。从其他基础项目移植而来的代码也要按同样方式处理。
  • 按依赖关系安排里程碑:
    1. 数据基础:ID、物品和方块注册表、模组核心数据(要素、研究);
    2. 核心机制;
    3. 装置、合成、世界生成和生物;
    4. 渲染和特效;
    5. 兼容性。 从第一天起就维护状态文档(第 7 节)。

3. 提取数据,不要手动重录

  • 注册代码其实是伪装成代码的数据(ConfigItems、ConfigResearch、配方类):
    • 使用小型分词器脚本解析反编译后的调用链,并将 JSON 写入移植项目的资源目录。
    • 在脚本中记录源代码行号。
    • 重新运行脚本,而不是手动编辑脚本的输出。
    • 在 Thaumcraft 移植项目中,这样提取出了 48 种要素、457 个物品要素注册项、包含页面和扭曲值的研究树,以及所有配方。
  • 旧版 ID。 旧物品通常以 (物品,元数据) 对表示,而新版引擎不再使用元数据。
    • 为每个组合分配一个扁平化 ID。
    • 让每个移植的物品注册其所替代的旧版引用。
    • 通过该映射解析数据文件中的引用。
    • 如果目录中有条目尚未注册,则在启动时失败。
    • 对于基础游戏中已重命名的 ID,使用目标端的数据修复器。
  • **统计所有内容:**测试每个原始物品和元数据变体是否存在,可以发现未被察觉的缺漏(Thaumcraft 移植项目中有 225 个物品 + 119 个方块物品)。
  • 保留原始顺序。 旧模组中的查找通常采用首次匹配:第一个匹配的配方或类别会胜出。数值也可能累积(例如在一次注册中重复添加要素)。提取器若对条目排序或覆盖映射键,就会改变行为。
  • 追踪尚未解析的引用。 每次处理后统计未解析引用的数量(Thaumcraft 移植项目中从 101 → 47 → 24),以免有内容一直被悄悄搁置。
  • 移植前确认原项目确实调用了相关代码。 在反编译内容中查找调用位置和发送位置,并记录死代码,以免后续审计将其算作缺失。Thaumcraft 4 发布了 7 个从未被调用的特效类和 3 个从未发送过的数据包。

4. 逐个单元移植

每个单元(方块、设备、生物、机制)都遵循相同步骤:

  1. 阅读原始类。
  2. 移植。
  3. 标记保留的怪癖。
  4. 编写测试。
  5. 运行测试。
  6. 在状态文档中记录该单元。
  7. 提交。
  • **保留可观察到的怪癖和 Bug,**并添加注释,指出原始类或代码行,以免下一个 Agent 将其“修复”。Thaumcraft 移植中的示例:

    • 按住某个按键会阻止所有方块的右键操作,因为原始实现会对每个方块都返回“已处理”;
    • 即使关闭了选项,Boss 仍会随机获得冠军修饰效果;
    • 带有容器物品的材料不会添加任何要素。

    但不要复现崩溃或客户端不同步问题。请逐一列出此类情况。

  • 记录每项强制偏离(引擎限制、已移除的 API)及其原因,并将其列入状态文档中的“已知偏离”清单。

  • 在日志中使用两个标签:

    • “保留的怪癖”:原始 Bug,出于有意而保留;
    • “偏离”:新引擎无法或不应复现的内容,并且必须附上原因。 后续读者便能区分保留的 Bug 与移植 Bug。
  • **原始代码继承自旧引擎。**子类可能继承自原版生物、原版树木生成器或旧版移动代码,而新引擎中的对应版本并不相同。也要移植旧引擎的相关部分,并关闭新父类新增的行为(在 Minecraft 中,1.20 的僵尸子类会获得转化为溺尸的能力)。

  • **标记凭记忆推断的平台行为。**Mod 的反编译代码中不包含旧引擎或加载器(Forge、原版 1.7.10)。凡是依据记忆得出的内容,都要标为 UNVERIFIED,或者也对旧引擎和加载器进行反编译。

  • **尚不存在的内容要使用替代项。**为每项缺失依赖添加具名钩子或标签,将其列为待处理,并在对应单元完成后接入。

  • **确保服务器具有权威性。**重新验证客户端曾由原始实现信任的请求。同时仍要移植原始实现的客户端预检查和消息。

  • **忠实度与可玩性之间如何取舍,由用户决定。**例如,在新地形上几乎无法通过的地点检查、新生态已不再需要的回退方案,以及超出原始内容的美术设计,都要记录为待用户决定的事项。不要擅自敲定。

  • **有意映射引擎概念。**不同版本之间,事件顺序、刻(tick)、元数据、渲染和世界生成都发生了变化。Minecraft 的对照表位于 references/minecraft-1-7-10-forge-to-1-20-fabric.md;移植过程中也要为你的引擎编写一份。

  • **绝不要凭记忆移植。**当 Wiki 与反编译结果不一致时,以反编译结果为准。

5. 从低成本到真实环境的验证方式

通用方法见 knowledge/techniques/oracles-how-agents-know-a-mod-works.md。移植时,按从低成本到真实环境的顺序:

  1. 在真实服务器上运行无头测试(Minecraft GameTests:runGametest)验证逻辑。解析 JUnit XML;不要轻信控制台输出。设置步骤和常见陷阱见: knowledge/techniques/fabric-1-20-1-gametests-as-the-oracle-of-a-large-mod-port.md。
    • **编写可能失败的测试。**选择错误行为会产生不同结果的输入,并在编写断言前读取原始实现的数值。
    • 每项测试都要清理自身位置周围的全局状态(测试间会泄漏共享状态)。
  2. 使用脚本控制真实客户端,测试点击流程、屏幕、渲染、自然世界生成和第二名玩家:knowledge/techniques/a-scenario-harness-in-a-minecraft-fabric-dev-client-real-cli.md。
    • 服务器测试会直接调用物品代码。它们无法发现移植时遗漏了原始的客户端预检查及其消息。
  3. **在真实服务器上运行发布版 jar 和真实整合包的 jar。**重映射、jar 嵌套和依赖冲突只有在此时才会显现。
  4. 由真人进行游戏流程测试,覆盖以上方式都无法验证的内容。请他人进行测试;不要声称已经测试。

请按系统如实报告证据等级:

  • 已实现;
  • 已测试;
  • 已在真实客户端中观察;
  • 未验证。

如果某次运行并未实际执行,绝不要写“通过”。如果主机或工具无法访问,请说明哪些测试没有运行。

6. 按层与原版进行审计

逐个功能开展工作会造成系统性偏差,单个测试无法发现这些问题。

  • 功能完成后,每次审计一层:
    • 事件处理器、数据包、物品、方块、实体、GUI;
    • 世界生成、战利品、研究与配方、配置;
    • 渲染器,细分为瓦片、方块、实体和物品。
  • 每次审计都作为只读检查运行。 它会将该层中的每个原版类与移植版本逐行比对,并返回按优先级排序的发现,注明文件和行号。
    • 并行安排多名审查者,每组一名,一轮即可覆盖一层。
    • 处理完待办事项后,重新运行对应的视觉场景。
    • 在所有游戏玩法测试都已通过后,Thaumcraft 渲染器审计仍发现了大约 60 处差异。
  • 每当更换基底或源版本后,运行一次遗留内容审计:搜索旧版本名称,并将每个纹理和模型与原始 jar 进行哈希比对。
  • 检查原版在客户端执行的检查:例如拒绝操作时显示聊天消息、工具提示、取消挥动。移植版本常常只保留服务器端的二次检查,导致操作被静默拒绝。

7. 让移植工作可续接

大型移植项目往往会超出单次会话的上下文容量。让仓库记录状态,并且先构建,再信任代码。有次会话在 Thaumcraft 移植中留下了转换到一半的代码:调用旧基底的方法、使用旧枚举值。每次会话开始时都要构建,并根据参考代码重新移植出错的调用,而不是用存根代替。

  • 状态文档(docs/MIGRATION_STATUS.md):
    • 原版的许可证,以及所需的作者许可;
    • 固定的版本和适配矩阵;
    • 按单元记录的日志:已移植的内容、原版类、保留的特性、差异、测试;
    • 已知的错误和差异;
    • 已知的未经验证区域;
    • 确切的下一项任务;
    • 根据证据级别而非提交数量估算完成度。
  • 简短的交接文档(docs/HANDOFF.md):项目现状、不可妥协的决策、命令、最近一次真实测试结果,以及需要用户回答的待解决问题。
  • Agent 说明(AGENTS.md),注明可信来源和验证规则。
  • **每个单元一个提交,**每次会话结束时推送(除非可以公开发布,否则推送到私有远程仓库)。 临时云容器会丢失所有未推送的内容。
  • 记录构建前置条件。 云环境必须允许加载器的 Maven 仓库和游戏厂商的下载主机访问。对于 Minecraft,这些主机包括 maven.fabricmc.net、piston-meta.mojang.com、piston-data.mojang.com、libraries.minecraft.net 和 resources.download.minecraft.net,以及每个依赖项的 Maven 仓库。缺少这些条件,首次 Gradle 构建就无法运行。
  • 随时记录实地笔记(docs/field-notes/):每条笔记记录一个事实,并附上证据。最后将它们整理为知识库笔记。

8. 分享

  • 为每次移植编写一份游戏笔记(um kb new):版本、移植路线、原版许可证及移植版本是否公开、注意事项。
  • 为可用于其他模组的方法编写技术笔记:渲染状态映射、测试框架、数据提取。
  • 参阅 share-field-notes 技能。任何 PR 之前都要先询问用户。

硬性规则(在 mod-any-game 的规则之上)

  • 除非原版许可证允许,否则不得随移植版本发布反编译参考代码和原版资源。
  • 只有在许可证允许,或作者(或现任权利持有人)已授予许可时,才能发布他人模组的移植版本。否则必须保持私有。无论如何都要注明原作者。
  • 不要因为实现更容易,就从模组的其他版本引入机制。
  • 不得声称运行过实际上并未运行的测试、构建或视觉检查。

评论

支持 Markdown