Files
mtgodot-poc/docs/PORT-PLAN.md
T
shenleiandClaude Opus 5 184b631ce8 docs: PORT-PLAN.md as the single entry for the 40250 port route
Records the decisions (mirror-layout logic port, embedded CPython 2.7 UI),
layers and code layout, batch route and status, and the directory/toolchain
setup needed to resume on another machine. Marks the older refactor plan as
superseded and points CLAUDE.md/AGENTS.md/roadmap at it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 18:20:14 +09:00

8.6 KiB
Raw Blame History

40250 1:1 移植:路线与方案

本文是移植工作的总入口,换一台电脑继续开发时先读这份。更新日期:2026-09-22。

  • 方法细则:.agents/skills/metin2-40250-parity-audit/SKILL.md(每轮的做法、状态定义、工具)
  • 批次队列:audit/remediation-roadmap.md
  • 逐函数进度:audit/port-map/**;每轮一行记录:audit/history.jsonl
  • Python UI 评估:docs/PYTHON-EMBED-EVAL.md
  • 旧方案 docs/CLIENT-REFACTOR-40250-PLAN.md("形式上不照搬类文件")已被本文取代

1. 目标与原则

metin2-client 是 40250 Windows 客户端的跨平台版本(macOS / Windows / Linux / Android / iOS)。 除渲染和平台 API 外,所有玩法算法、分支、常量、状态顺序、计时来源、数据来源、封包副作用和清理路径都以 40250 为准。40250 源码就是规格,不设计行为,只照抄。

  • 工作单位是 40250 的一个源文件(或超大文件里的一组函数),不是某个行为分支。
  • 当前代码里没有 40250 对应物的逻辑是缺陷,要删掉。
  • 运行时不会加载的代码不算实现,它的测试也不算证据。

2. 已定的决定

日期 决定 依据
2026-09-22 逻辑层按 40250 结构移植:C++ → C++,文件名、类名、方法名、成员名、语句顺序都保持一致 能逐文件机械核对,不再"找差异"
2026-09-22 UI 走内嵌 CPython 2.7.18(方案 A),原样运行 40250 的 root/*.pyuiscript/,只移植 C++ 模块 脚本无需改动;macOS 和 Android 真机均已验证,见 docs/PYTHON-EMBED-EVAL.md
2026-09-22 UI 参考源是 40250 的 Client/Eternexus/root不是仓库里的 assets/rootm2dev 版本) 两者有实质差异
2026-09-22 现有 project/ui/*.gd(60 个文件,依据的是错误版本的脚本)不再维护,由 Python 层取代

3. 三个层和代码位置

40250 单元 做法 位置
logic UserInterface/GameLib/EterLib 的网络/计时/文本解析、EterPackEterLocale 逐文件照抄 C++ extension/src/port/<Lib>/<File>.{h,cpp}
python root/*.pyuiscript/UserInterface/*Module.cppEterPythonLib/ScriptLib/ 脚本原样运行;*Module.cpp、窗口系统、CPythonLauncher 照抄 extension/src/port/<Lib>/ + extension/third_party/cpython-2.7.18/
platform Direct3D/Grp*、Granny、Miles、SpeedTree、特效/地形渲染、Win32 窗口/输入/IME、线程、反作弊 适配层,接口与 40250 调用方看到的一致,按可观察输出核对 extension/src/platform/ + 现有渲染代码
extension/src/port/UserInterface/InstanceBase.cpp      # 40250 同名文件的照抄
extension/src/port/GameLib/ActorInstance.cpp
extension/src/port/ScriptLib/PythonLauncher.cpp
extension/src/port/EterPythonLib/PythonWindow*.cpp
extension/src/port/UserInterface/*Module.cpp           # app/net/player/chr/... Python 模块
extension/src/platform/                                # CGraphicThingInstance、CSoundManager 等同名适配接口
extension/third_party/cpython-2.7.18/                  # 静态库(2P 批次加入)

逻辑层规则:

  • 40250 调用平台类的地方,调用 extension/src/platform/ 下同名的适配接口,ported 代码里不直接写 Godot 调用。
  • 40250 的单例(CPythonPlayerCPythonCharacterManagerCPythonNetworkStream)归扩展所有,GDScript 不持有玩法状态。
  • 单位保持 40250 的(TPixelPosition 用 cm,时间是 ELTimer_GetMSec 的毫秒,角度用度),只在适配层换算。
  • net_play.gdnet_world.gdgame_scene.gdplayer_controller.gdentity_store.cpp 是迁移来源:移植某个单元的那次提交,同时删掉它们里面被取代的逻辑,只留胶水(建节点、转发输入、读状态摆节点)。
  • 迁移结束后 Godot 这边只剩:场景节点、渲染适配、一个把输入转发给 CPythonWindowManager 并每帧调用 Update/Render 的宿主 Control。

4. 路线

批次 内容 状态
0 工具:参考根解析、port_map.py、构建/测试入口 完成(55f733fd、5afd5a4f
1 删除运行时不加载的 106 个 *_system.gd 及其测试 完成(a989b8f1
定下目录结构,评估内嵌 Python 完成(9d0e50de
内嵌 Python Android 真机验证 完成(b02c49bb
2 P0 角色/移动单元照抄到镜像文件;第一个单元负责建立 port/platform/ 和 CMake 目标 下一步,未开始
2P CPython 2.7.18 编进 libmtgodotmacOS → Android APK → iOS 下一步,未开始,可与 2 并行
3 P1 战斗/技能 → P2 游戏阶段封包 → P3 物品;Python 层(PythonLauncher → 窗口系统 → *Module.cpp 未开始
4 NEEDS_LIVE 真服验证 未开始

批次 2:P0 单元(每个单元一个 worktree,互不共享实现文件的可并行)

  1. UserInterface/PythonPlayerEventHandler.cppOnMove/OnMoving/OnStop 已在 net_play.gd 对齐,需迁到镜像文件;OnWaiting 标为 DIVERGENT
  2. UserInterface/InstanceBaseMovement.cpp + InstanceBase.cpp(串行)
  3. UserInterface/PythonPlayerInput*.cpp(排在第 2 项之后)
  4. GameLib/ActorInstanceMotion.cpp + ActorInstanceEvent.cpp
  5. GameLib/ActorInstance.cpp + Position/Rotation/CollisionDetection
  6. UserInterface/PythonCharacterManager.cpp
  7. UserInterface/PythonPlayer.cpp

每轮的步骤(详见 SKILL.md):port_map.py init/show → 通读参考文件 → 照抄到镜像文件,逐函数与旧实现对比、 记录差异 → 删旧逻辑、改调用方 → 只为改动的公式/分支写测试 → 更新 port-map 和 history → 一个单元一次提交。

批次 2P:内嵌 Python 集成

  1. 把 CPython 2.7.18 源码放进 extension/third_party/cpython-2.7.18/,用我们自己的 CMake 编译。macOS/Android/iOS 共用一份源码清单和 pyconfig.hAndroid 需关掉 HAVE_LANGINFO_H),C 模块清单见 tools/py_embed_android/build-and-run.sh
  2. 静态链接进 libmtgodot,照抄 ScriptLib/PythonLauncher.cpp
  3. pack 模块通过 asset_io 读取,标准库的纯 Python 文件放进资源包,由 system.py 自带的导入钩子加载
  4. 先用桩 C++ 模块在 APK 进程里跑通 system.pyprototype.RunApp()(对照结果:74 个模块中 66 个加载成功,引导期调用 33 个 C++ 函数)
  5. 同样的流程在 iOS 上跑一遍

5. 当前进度

实时数字用 port_map.py status 查看。2026-09-22 的状态:

函数数 已完成
logic 3285 6
python 4890 0(其中 Client/root 的 3350 个在 2P 完成后记为 N_A,属于原样运行)
platform 2229 0

6. 换机器后的环境准备

目录布局(路径都相对 ~/Work/mt/,工具按相对路径查找):

~/Work/mt/metin2-client/                     # 本仓库(git remote origin
~/Work/mt/40250/Server Client TMP4/          # 40250 参考(不在 git 里,需自行复制)
    ClientVS22/source/                       # C++ 参考根(audit/manifest.json 的 reference_root
    Client/Eternexus/root, uiscript, locale  # Python 参考
~/Work/mt/metin2-client/assets/, bgm/        # 游戏资源(gitignored,需自行复制;或用 MT_ASSETS 指到别处)
  • 参考源放在其他位置时,设置 MT_40250_SOURCE=<.../ClientVS22/source>
  • Python 2.7.18:用于运行 py_embed_spike.py。macOS 安装 python.org 的 2.7.18 包,确认 python2.7 --version
  • Python 3:用于 port_map.py 和其他审计脚本。
  • AndroidNDK 27.2ANDROID_NDK_HOME 指向它;未设置时脚本选版本号最低的 NDK)、openjdk@21、Godot 导出模板; adb/opt/homebrew/bin/adb。APK 导出用 ./export-android.sh
  • 真服账号、密码不写进仓库或 audit 账本。

新会话恢复工作:

cd ~/Work/mt/metin2-client
git pull
python3 .agents/skills/metin2-40250-parity-audit/scripts/port_map.py status
python3 .agents/skills/metin2-40250-parity-audit/scripts/port_map.py queue --limit 20
python3 .agents/skills/metin2-40250-parity-audit/scripts/port_map.py check
python2.7 .agents/skills/metin2-40250-parity-audit/scripts/py_embed_spike.py --out /tmp/py_embed_spike.txt   # 可选:复核 Python 原型
tools/py_embed_android/build-and-run.sh                                                         # 可选:连接 Android 真机复核

然后按第 4 节的"下一步"继续,一个单元完成后在第 4、5 节更新状态并提交。