port-a-mod

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Port a mod faithfully

忠实移植 mod

When porting an existing mod, the original is the spec. A port rarely fails for lack of code. It fails by drift:
  • values recalled from memory or a wiki;
  • mechanics borrowed from a later rewrite of the same mod;
  • quiet "improvements";
  • renderers that look roughly right;
  • checks that the original made on the client and the port forgot.
The method below carried a Thaumcraft 4.2.3.5 port from Minecraft 1.7.10 Forge to 1.20.1 Fabric:
  • 859 original classes became about 77,000 lines of port code;
  • 323 GameTests cover it, and scripted real-client scenarios check what tests can't reach;
  • the work spanned many sessions and two agent accounts.
The field note
knowledge/games/minecraft/porting-thaumcraft-4-1-7-10-forge-to-minecraft-1-20-1-fabric.md
has its gotchas. Minecraft-specific mappings are in
references/minecraft-1-7-10-forge-to-1-20-fabric.md
.
Run the mod-any-game loop around this skill (intake, recon, lab, verify, publish, field note). This skill replaces its "vertical slice" step with a long series of slices, one per unit of the original. Bringing one game's content or mechanics into another game is the mashup-mods skill, not this one.
移植现有 mod 时,原作就是规格基准。移植失败很少是因为缺少代码;更常见的原因是发生漂移(drift):
  • 凭记忆或 wiki 记下的数值;
  • 从同一 mod 的后续重写版本中借鉴的机制;
  • 悄悄进行的“改进”;
  • 仅大致正确的渲染器;
  • 原作会在客户端执行、而移植版遗漏的检查。
以下方法曾支撑一次 Thaumcraft 4.2.3.5 移植,将 Minecraft 1.7.10 Forge 上的 mod 移植到 1.20.1 Fabric:
  • 859 个原始类最终形成约 77,000 行移植代码;
  • 323 个 GameTests 覆盖移植结果,脚本驱动的真实客户端场景负责检查测试无法覆盖的部分;
  • 工作跨越多个会话和两个 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
。
围绕本 skill 运行 mod-any-game 循环(intake、recon、lab、verify、publish、field note)。本 skill 将其“vertical slice”步骤替换为一系列长期进行的 slices,每个 slice 对应原作的一个单元。将一款游戏的内容或机制引入另一款游戏属于 mashup-mods skill 的范畴,而不是本 skill。

Before you start: the license

开始前:许可证

The original's code and assets belong to its author. A port is built from them, often from a decompile of them, so the original's license decides what of the port can be published. (This isn't legal advice; when in doubt, ask the author.)
  • Find the license of the release you will port: the mod's repository (
    LICENSE
    ), its mod page, the files in the jar, or the author's release post. Write it into the status document (section 7), with the link.
  • An open license (MIT, LGPL, GPL, a Creative Commons license): follow its terms. Keep the copyright notices, credit the author, and use the same license where it requires that (GPL, LGPL, CC BY-SA).
  • All rights reserved, no license at all, or a "no ports" clause: publishing anything of the port (a jar, a public repository, the original's textures or sounds) needs the permission of the author or the current rights holder. Ask them, and keep their answer (a link or a quote) in the status document. With no permission, the port stays private.
    • Thaumcraft 4, the worked example here, is closed source. In 2014 its author had a decompiled copy taken off GitHub (DMCA notice).
  • Tell the user which case it is before starting. A private port for their own pack is their call.
  • Credit the original author in the port and in any release, and don't present the port as an official version.
原作的代码和资源归其作者所有。移植版本以这些内容为基础构建,而且往往直接来自它们的反编译结果,因此原作的许可证决定了移植版本中哪些内容可以发布。(这不是法律意见;如有疑问,请咨询作者。)
  • 查找将要移植的发布版本所采用的许可证:mod 的仓库(
    LICENSE
    )、mod 页面、jar 中的文件,或作者的发布帖子。将其及链接写入状态文档(第 7 节)。
  • 开放许可证(MIT、LGPL、GPL、Creative Commons):遵守其条款。保留版权声明、标注原作者,并在许可证要求时使用相同许可证(GPL、LGPL、CC BY-SA)。
  • **保留所有权利、未提供任何许可证,或包含“禁止移植”条款:**要发布移植版本中的任何内容(jar、公开仓库、原作的纹理或音效),都需要作者或当前权利持有人的许可。征求许可,并将答复(链接或引用)保存在状态文档中。未获得许可时,移植版本必须保持私有。
    • 此处使用的 Thaumcraft 4 案例是闭源项目。2014 年,其作者的一份额本从 GitHub 下架(DMCA 通知)。
  • **开始前告诉用户属于哪种情况。**为用户自己的整合包制作私有移植由用户自行决定。
  • 在移植版本及任何发布内容中标注原作者,不要将移植版本描述为官方版本。

0. Pin one source of truth

0. 固定唯一事实来源

  • Pin the exact release: the jar, its hash (SHA-1), where it came from and its changelog. For a dead mod line, the last release is usually the right one.
  • Use one version as the reference, and only one. A later rewrite with the same name (Thaumcraft 5 and 6 against 4, a "Reborn" or "Legacy" fork) is a different mod.
    • The Thaumcraft port started from the wrong base and switched mid-way.
    • Weeks later, TC5 meshes, textures, an input handler and a swing hook were still in the code, although every audit had compared gameplay with TC4.
    • If the base ever changes, archive the old state, sort every area into keep / adapt / replace / remove, and grep comments and identifiers for the old version's name.
  • Write the rule where every future agent reads it: the project's
    AGENTS.md
    (point any agent-specific instructions file at it). Example: "<mod> <version> is the only gameplay source. Keep its values, quirks and observable bugs. Later versions are not references. Do not silently improve gameplay. Never claim a build or test passed unless it ran."
  • **锁定准确的发布版本:**jar 文件、其哈希值(SHA-1)、获取来源以及更新日志。对于已经停止维护的 mod 系列,通常应选择最后一个发布版本。
  • **只使用一个版本作为参考,而且只能有一个。**同名 mod 的后续重写版本(相对于 Thaumcraft 4 的 Thaumcraft 5 和 6,或“Reborn”“Legacy”分支)是另一个 mod。
    • Thaumcraft 移植最初选错了基线,并在中途更换。
    • 数周后,代码中仍残留 TC5 的网格、纹理、输入处理器和挥动钩子,尽管每次审计都比对的是 TC4 的 gameplay。
    • 如果基线发生变化,应归档旧状态,将每个领域归类为保留/适配/替换/移除,并使用 grep 搜索注释和标识符中的旧版本名称。
  • **将规则写在每个后续 Agent 都会读取的位置:**项目的
    AGENTS.md
    (让所有 Agent 专用说明文件指向它)。示例: “<mod> <version> 是唯一的 gameplay 来源。保留其数值、特殊表现和可观察到的 bug。后续版本不是参考。不得在未说明的情况下改进 gameplay。除非确实运行过,否则绝不能声称构建或测试已通过。”

1. Build a private reference

1. 建立私有参考

  • If the original's source is published (its repository, a sources jar), work from the source at the pinned release's tag, and decompile the jar only to check that the two match.
  • Decompile with Vineflower first. Fall back to CFR for the classes it fails on, and count those classes. The reverse-engineering skill has the tools.
  • Remap to readable names:
    • 1.7.10 Forge jars ship SRG names (
      func_12345_a
      ,
      field_1234_b
      ). Remap them with the MCP
      stable_12
      CSVs (
      methods.csv
      ,
      fields.csv
      ); a token-replacing script is enough. 1.12 uses
      stable_39
      .
    • On the target side, read the mapped game jar from the loader's cache with
      javap
      . It shows names, lambda names and local-variable slots for mixins. Loom's
      genSources
      gives readable source.
  • Extract the original assets (textures, models, lang, sounds) next to the decompile, so asset audits can hash against them.
  • Keep it private. The decompile never ships, and is never committed to a public repo (hard rule).
    • Do keep it reachable by every future session: a separate private repository, or a fixed folder outside the port's repository.
    • Keep it out of the port's own history. A repository made public later publishes its whole history.
    • The Thaumcraft port kept
      reference/
      in its private repository, so every fresh cloud session could read the original before changing anything.
  • 如果原作的源码已经公开(其仓库或 sources jar),应以固定发布版本的 tag 下的源码为依据,并仅反编译 jar,以核对两者是否一致。
  • 首先使用 Vineflower 反编译。对于它无法处理的类,回退到 CFR,并统计这些类的数量。reverse-engineering skill 提供了所需工具。
  • 重映射为可读名称:
    • 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
      读取 loader 缓存中经过映射的游戏 jar。其中会显示名称、lambda 名称,以及 mixin 所需的局部变量槽位。Loom 的
      genSources
      可生成可读源码。
  • 提取原作资源(纹理、模型、语言文件和音效),放在反编译结果旁,以便资产审计时进行哈希核对。
  • **保持私有。**反编译结果绝不随发布物分发,也绝不提交到公开仓库。
    • 但要让每个后续会话都能访问它:使用单独的私有仓库,或将其放在移植仓库之外的固定目录中。
    • 不要让它进入移植仓库自身的 Git 历史。仓库以后公开时,会连同全部历史一起公开。
    • Thaumcraft 移植将
      reference/
      保存在其私有仓库中,因此每个新的云端会话都能在修改前读取原作。

2. Inventory and adaptation matrix

2. 清单与适配矩阵

  • List every subsystem of the original: registries, event handlers, packets, GUIs and screens, renderers, world generation, loot, config, commands, public API, compat hooks.
  • Write the matrix: for each area, the original classes, the port classes, and a verdict (keep / adapt / replace / remove / missing). Port code that came from another base gets the same treatment.
  • Order the milestones by dependency:
    1. data foundations: ids, the item and block registry, the mod's core data (aspects, research);
    2. core mechanics;
    3. devices, crafting, world generation and mobs;
    4. rendering and FX;
    5. compat. Keep a status document from day one (section 7).
  • **列出原作的每个子系统:**注册表、事件处理器、数据包、GUI 与 screens、渲染器、世界生成、战利品、配置、命令、public API 和兼容 hooks。
  • **编写矩阵:**对于每个领域,记录原始类、移植版类,以及结论(保留/适配/替换/移除/缺失)。来自其他基线的移植代码也应采用相同方式处理。
  • 按依赖关系排列里程碑:
    1. 数据基础:ids、物品与方块注册表、mod 的核心数据(aspects、research);
    2. 核心机制;
    3. 设备、合成、世界生成和生物;
    4. 渲染与 FX;
    5. 兼容性。 从第一天起维护状态文档(第 7 节)。

3. Extract data; don't retype it

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

  • Registration code is data in disguise (
    ConfigItems
    ,
    ConfigResearch
    , recipe classes):
    • Parse the decompiled call chains with a small tokenizer script, and write JSON into the port's resources.
    • Note the source line numbers in the script.
    • Re-run the script instead of hand-editing its output.
    • In the Thaumcraft port this produced the 48 aspects, 457 object-aspect registrations, the research tree with its pages and warp, and every recipe.
  • Legacy ids. Old items are often
    (item, metadata)
    pairs, and newer engines have no metadata.
    • Give each pair one flattened id.
    • Have each ported item register the legacy reference it replaces.
    • Resolve references in data files through that map.
    • Fail at startup when a catalogue entry is left unregistered.
    • For the base game's own renamed ids, use the target's data fixer.
  • Count everything: a test that every original item and metadata variant exists catches silent gaps (225 items + 119 block items in the Thaumcraft port).
  • Keep the original order. Lookups in old mods are often first-match: the first matching recipe wins, and the first matching category. Values can also accumulate (an aspect added twice in one registration). An extractor that sorts entries or overwrites map keys changes behaviour.
  • Track what can't be resolved yet. Count the unresolved references after each pass (101 → 47 → 24 in the Thaumcraft port as content arrived), so nothing waits silently.
  • Check that the original ever calls the code before porting it. Find its call sites and send sites in the decompile, and record the dead code so later audits don't count it as missing. Thaumcraft 4 shipped 7 FX classes that were never called and 3 packets that were never sent.
  • 注册代码本质上是伪装成代码的数据(
    ConfigItems
    、
    ConfigResearch
    、配方类):
    • 使用小型 tokenizer 脚本解析反编译后的调用链,并将 JSON 写入移植版本的 resources。
    • 在脚本中记录来源行号。
    • 重新运行脚本,而不是手动编辑其输出。
    • 在 Thaumcraft 移植中,这一过程生成了 48 个 aspects、457 个 object-aspect 注册项、包含页面和 warp 的研究树,以及所有配方。
  • **旧版 ids。**旧物品通常是
    (item, metadata)
    对,而新引擎没有 metadata。
    • 为每一对分配一个扁平化 id。
    • 让每个移植后的物品注册它所替代的旧版引用。
    • 通过该映射解析数据文件中的引用。
    • 如果目录项没有注册,应在启动时失败。
    • 对于游戏本体自身重命名的 ids,使用目标端的 data fixer。
  • **对所有内容进行计数:**通过测试确认每个原始物品和 metadata 变体都存在,可以发现静默缺失(Thaumcraft 移植中为 225 个物品和 119 个 block items)。
  • **保持原始顺序。**旧 mod 中的查找通常采用首个匹配项:第一个匹配的配方生效,第一个匹配的分类生效。数值也可能累加(例如在某次注册中同一个 aspect 被添加两次)。如果提取器对条目排序或覆盖 map keys,就会改变行为。
  • **跟踪暂未解析的内容。**每轮之后统计未解析的引用数量(Thaumcraft 移植中为 101 → 47 → 24),避免任何内容一直处于无人处理的状态。
  • **移植前先确认原作是否调用过相关代码。**在反编译结果中查找调用点和发送点,并记录死代码,避免后续审计将其误判为缺失。Thaumcraft 4 包含 7 个从未被调用的 FX 类和 3 个从未被发送的数据包。

4. Port unit by unit

4. 逐单元移植

Each unit (a block, a device, a mob, a mechanic) follows the same steps:
  1. Read the original classes.
  2. Port them.
  3. Mark kept quirks.
  4. Write a test.
  5. Run it.
  6. Log the unit in the status document.
  7. Commit.
  • Keep observable quirks and bugs, with a comment that names the original class or line, so the next agent does not "fix" them. Examples from the Thaumcraft port:
    • holding a key stops every block's right-click, because the original's key answered "handled" for every block;
    • bosses roll champion modifiers with the option off;
    • an ingredient with a container item adds no aspects.
    Don't reproduce crashes or client desync glitches, though. List each such case.
  • Document every forced deviation (an engine limit, a removed API) with its reason, in the status document's "known deviations" list.
  • Use two labels in the log:
    • "quirk kept": an original bug, preserved on purpose;
    • "deviation": something the new engine cannot or should not reproduce, always with the reason. A later reader can then tell a kept bug from a port bug.
  • The original inherited code from the old engine. A subclass of a vanilla mob, a vanilla tree generator, the old movement code: the new engine's versions differ. Port the old engine's parts too, and switch off what the new superclass adds (in Minecraft, a 1.20 zombie subclass gains drowned conversion).
  • Mark recalled platform behaviour. The mod's decompile does not contain the old engine or loader (Forge, vanilla 1.7.10). Mark anything taken from memory of them UNVERIFIED, or decompile them too.
  • Use stand-ins for content that doesn't exist yet. Give each missing dependency a named hook or tag, list it as pending, and wire it when its unit lands.
  • Keep the server authoritative. Re-validate client requests the original trusted. Still port the original's client-side pre-checks and messages.
  • Fidelity against playability is the user's call. A site check that almost never passes on new terrain, a fallback the new ecosystem makes redundant, art beyond the original: log each as an open user decision. Don't settle it silently.
  • Map engine concepts deliberately. Event order, ticking, metadata, rendering and world generation all changed between versions. The Minecraft table is in
    references/minecraft-1-7-10-forge-to-1-20-fabric.md
    ; write one for your engine as you go.
  • Never port from memory. When the wiki and the decompile disagree, the decompile wins.
每个单元(一个方块、一台设备、一种生物或一项机制)都遵循相同的步骤:
  1. 阅读原始类。
  2. 移植这些类。
  3. 标记要保留的特殊行为。
  4. 编写测试。
  5. 运行测试。
  6. 在状态文档中记录该单元。
  7. 提交。
  • **保留可观察到的特殊行为和 bug,**并添加注释,注明原作的类或行号,防止后续 Agent 擅自“修复”。Thaumcraft 移植中的示例:
    • 按住 key 会阻止所有方块的右键操作,因为原版 key 会对每个方块返回“handled”;
    • 即使相关选项已关闭,Boss 仍会 roll 出 champion modifiers;
    • 带有 container item 的 ingredient 不会增加 aspects。
    但不要复现崩溃或客户端 desync 故障。逐一列出此类情况。
  • 记录所有强制偏差(引擎限制、已移除的 API),并在状态文档的“known deviations”列表中写明原因。
  • 在日志中使用两个标签:
    • quirk kept
      :有意保留的原作 bug;
    • deviation
      :新引擎无法或不应复现的内容,必须附上原因。 这样,后续读者便能区分有意保留的 bug 和移植缺陷。
  • **原作从旧引擎继承了代码。**vanilla mob 的子类、vanilla 树木生成器、旧移动代码等,在新引擎中的实现已经不同。旧引擎的相关部分也要移植,并禁用新 superclass 新增的行为(例如在 Minecraft 中,1.20 的 zombie 子类会获得 drowned 转换能力)。
  • **标记凭记忆推测的平台行为。**mod 的反编译结果不包含旧引擎或 loader(Forge、vanilla 1.7.10)。对于凭记忆了解的行为,应标记为 UNVERIFIED,或对这些引擎一并进行反编译。
  • **为尚不存在的内容使用替身。**为每个缺失的依赖提供命名 hook 或 tag,将其列为待处理,并在对应单元完成时接入。
  • **保持服务端权威。**重新校验原作所信任的客户端请求,同时仍要移植原作的客户端预检查和消息。
  • **忠实度与可玩性的取舍由用户决定。**对于在新地形上几乎无法通过的 site check、新生态已使其变得多余的 fallback,以及超出原作范围的美术内容,应将每一项记录为待用户决定事项。不要擅自作出决定。
  • **有意识地映射引擎概念。**事件顺序、ticking、metadata、渲染和世界生成在不同版本之间均发生了变化。Minecraft 对照表位于
    references/minecraft-1-7-10-forge-to-1-20-fabric.md
    ;同时为所用引擎编写对应表格。
  • **绝不要凭记忆移植。**当 wiki 与反编译结果不一致时,以反编译结果为准。

5. Oracles, from cheap to real

5. 验证依据(Oracles):从低成本到真实环境

The general method is in
knowledge/techniques/oracles-how-agents-know-a-mod-works.md
. For a port, from cheap to real:
  1. Headless tests on the real server (Minecraft GameTests:
    runGametest
    ) for logic. Parse the JUnit XML; don't trust the console. Setup and traps:
    knowledge/techniques/fabric-1-20-1-gametests-as-the-oracle-of-a-large-mod-port.md
    .
    • Write tests that can fail. Pick inputs where the wrong behaviour gives a different answer, and read the original's values before writing the assertion.
    • Each test cleans up the global state around its own position (shared state leaks between tests).
  2. A scripted real client for the click path, screens, rendering, natural world generation and a second player:
    knowledge/techniques/a-scenario-harness-in-a-minecraft-fabric-dev-client-real-cli.md
    .
    • Server tests call the item code directly. They can't see that the port dropped the original's client-side pre-check and its message.
  3. The release jar on a real server, and the real modpack's jars. Remapping, jar-in-jar and dependency clashes only show up there.
  4. A human playthrough for what nothing above covers. Ask for it; don't claim it.
Report evidence levels honestly, per system:
  • implemented;
  • tested;
  • seen in a real client;
  • unverified.
Never write "passes" for a run that did not happen. If a host or tool is unreachable, say what was not run.
通用方法位于
knowledge/techniques/oracles-how-agents-know-a-mod-works.md
。对于移植,应按成本从低到高采用以下手段:
  1. 真实服务器上的 headless 测试(Minecraft GameTests:
    runGametest
    )用于验证逻辑。解析 JUnit XML;不要相信控制台输出。设置与陷阱见:
    knowledge/techniques/fabric-1-20-1-gametests-as-the-oracle-of-a-large-mod-port.md
    。
    • **编写可能失败的测试。**选择错误行为会产生不同结果的输入,并在编写断言前读取原作的数值。
    • 每个测试都应清理自身位置周围的全局状态,避免共享状态在测试之间泄漏。
  2. 脚本驱动的真实客户端用于验证点击路径、screens、渲染、自然世界生成和第二名玩家:
    knowledge/techniques/a-scenario-harness-in-a-minecraft-fabric-dev-client-real-cli.md
    。 服务器测试直接调用物品代码,因此无法发现移植版遗漏了原作的客户端预检查及其消息。
  3. **在真实服务器上运行发布 jar,并使用真实 modpack 中的 jar。**重映射、jar-in-jar 和依赖冲突只有在这里才会暴露。
  4. 人工试玩用于覆盖以上手段无法处理的内容。应主动请求人工试玩,不要自行声称已经完成。
应按系统诚实地报告证据级别:
  • 已实现(implemented);
  • 已测试(tested);
  • 已在真实客户端中观察(seen in a real client);
  • 未验证(unverified)。
绝不要为未实际运行的测试写“通过”。如果主机或工具无法访问,应明确说明哪些内容没有运行。

6. Audit against the original, by layer

6. 逐层与原作审计

Feature-by-feature work leaves systematic drift that no single test sees.
  • Audit one layer at a time once features exist:
    • event handlers, packets, items, blocks, entities, GUIs;
    • world generation, loot, research and recipes, config;
    • renderers, split into tile, block, entity and item.
  • Run each audit as a read-only review. It compares every original class in the layer with its port line by line and returns ranked findings with file and line.
    • Several reviewers in parallel, one per group, cover a layer in one pass.
    • Fix the queue, then re-run the matching visual scenario.
    • The Thaumcraft renderer audit found about 60 differences, after every gameplay test was already green.
  • Run a leftover audit after any change of base or source version: grep for the old version's name, and hash every texture and model against the original jar.
  • Look for checks the original ran on the client: refusals with a chat message, tooltips, a cancelled swing. Ports often keep only the server re-check, which refuses silently.
逐功能推进会留下任何单项测试都无法发现的系统性漂移。
  • 功能存在后,逐层进行审计:
    • 事件处理器、数据包、物品、方块、实体、GUI;
    • 世界生成、战利品、research 与配方、配置;
    • 渲染器,分为 tile、block、entity 和 item。
  • **每次审计都作为只读审查运行。**逐行比较该层中的每个原始类与移植版,并返回按严重程度排序的发现结果,同时注明文件和行号。
    • 多名审查者可以并行工作,每组负责一组内容,在一次审查中覆盖一层。
    • 修复问题队列后,重新运行对应的可视化场景。
    • Thaumcraft 渲染器审计发现了约 60 处差异,而当时所有 gameplay 测试均已通过。
  • **更换基线或源版本后,运行遗留项审计:**使用 grep 搜索旧版本名称,并将每个纹理和模型与原始 jar 进行哈希核对。
  • **查找原作在客户端执行的检查:**带聊天消息的拒绝操作、tooltips、取消的挥动。移植版通常只保留服务端重新检查,导致拒绝时没有任何提示。

7. Keep the port resumable

7. 让大型移植可续接

A big port outlives any one session's context. Make the repo carry the state, and build before trusting it. A session left half-converted code in the Thaumcraft port: calls to methods of the old base, old enum values. Build at the start of every session, and re-port broken calls from the reference instead of stubbing them.
  • Status document (
    docs/MIGRATION_STATUS.md
    ):
    • the original's license, and the author's permission if one was needed;
    • the fixed versions and the adaptation matrix;
    • a per-unit log: what was ported, the original classes, kept quirks, deviations, tests;
    • known bugs and deviations;
    • known unverified areas;
    • the exact next task;
    • a completion estimate by evidence level, not by commit count.
  • A short handoff document (
    docs/HANDOFF.md
    ): where things are, the non-negotiable decisions, the commands, the latest real test result, and the open questions for the user.
  • Agent instructions (
    AGENTS.md
    ) with the source-of-truth and verification rules.
  • One commit per unit, pushed every session (to a private remote unless the port may be published). Ephemeral cloud containers lose anything not pushed.
  • Build prerequisites written down. A cloud environment needs the loader's Maven and the game vendor's download hosts allowed. For Minecraft that is
    maven.fabricmc.net
    ,
    piston-meta.mojang.com
    ,
    piston-data.mojang.com
    ,
    libraries.minecraft.net
    and
    resources.download.minecraft.net
    , plus each dependency's Maven. Without them, the first Gradle build can't run.
  • Field notes as you go (
    docs/field-notes/
    ): one fact per note, with its evidence. They become the knowledge-base notes at the end.
大型移植的生命周期会长于任何一个会话的上下文。让仓库承载状态,并且先构建,再信任它。Thaumcraft 移植中曾有一个会话留下转换到一半的代码:仍调用旧基线的方法,并使用旧枚举值。每次会话开始时都应构建,并从参考实现重新移植损坏的调用,而不是用 stub 掩盖问题。
  • 状态文档(
    docs/MIGRATION_STATUS.md
    ):
    • 原作的许可证,以及需要时作者给出的许可;
    • 固定版本和适配矩阵;
    • 按单元记录的日志:移植内容、原始类、保留的特殊行为、偏差和测试;
    • 已知 bug 和偏差;
    • 已知未验证领域;
    • 精确的下一步任务;
    • 按证据级别而非 commit 数量估算完成度。
  • 简短交接文档(
    docs/HANDOFF.md
    ):当前进度、不可协商的决策、命令、最近一次真实测试结果,以及待用户解答的问题。
  • Agent 说明(
    AGENTS.md
    ):包含事实来源和验证规则。
  • **每个单元一个 commit,**并在每次会话结束时推送(除非移植版本可以发布,否则推送到私有 remote)。临时云容器会丢失所有未推送的内容。
  • **记录构建先决条件。**云环境需要允许访问 loader 的 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. Share

8. 分享

  • Write one game note per port (
    um kb new
    ): versions, route, the original's license and whether the port is public, gotchas.
  • Write technique notes for methods that apply to other mods: render-state mapping, test harnesses, data extraction.
  • See the share-field-notes skill. Ask the human before any PR.
  • 为每次移植编写一篇游戏笔记(
    um kb new
    ):记录版本、移植路线、原作许可证、移植版本是否公开,以及相关陷阱。
  • 为可应用到其他 mod 的方法编写技术笔记:渲染状态映射、测试 harness、数据提取等。
  • 参考 share-field-notes skill。创建任何 PR 前,先询问用户。

Hard rules (on top of mod-any-game's)

硬性规则(除 mod-any-game 的规则之外)

  • The decompiled reference and the original's assets never ship unless the original's license allows it.
  • A port of someone else's mod is published only if its license allows it or its author (or the current rights holder) has given permission. Otherwise it stays private. Credit the original author either way.
  • Don't import mechanics from a different version of the mod because they are easier to implement.
  • Don't claim a test, build or visual check that did not run.
  • 除非原作的许可证允许,否则反编译参考和原作资源绝不能随发布物分发。
  • 他人 mod 的移植版本只有在许可证允许,或作者(当前权利持有人)给予许可时才能发布;否则必须保持私有。无论如何,都应标注原作者。
  • 不要因为其他版本的机制更容易实现,就将其导入移植版本。
  • 不要声称运行过实际上没有运行的测试、构建或可视化检查。