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

133 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/*.py``uiscript/`,只移植 C++ 模块 | 脚本无需改动;macOS 和 Android 真机均已验证,见 `docs/PYTHON-EMBED-EVAL.md` |
| 2026-09-22 | UI 参考源是 40250 的 `Client/Eternexus/root`**不是**仓库里的 `assets/root`(m2dev 版本) | 两者有实质差异 |
| 2026-09-22 | 现有 `project/ui/*.gd`(60 个文件,依据的是错误版本的脚本)不再维护,由 Python 层取代 | — |
## 3. 三个层和代码位置
| 层 | 40250 单元 | 做法 | 位置 |
| --- | --- | --- | --- |
| `logic` | `UserInterface/``GameLib/``EterLib` 的网络/计时/文本解析、`EterPack``EterLocale` | 逐文件照抄 C++ | `extension/src/port/<Lib>/<File>.{h,cpp}` |
| `python` | `root/*.py``uiscript/``UserInterface/*Module.cpp``EterPythonLib/``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 的单例(`CPythonPlayer``CPythonCharacterManager``CPythonNetworkStream`)归扩展所有,GDScript 不持有玩法状态。
- 单位保持 40250 的(`TPixelPosition` 用 cm,时间是 `ELTimer_GetMSec` 的毫秒,角度用度),只在适配层换算。
- `net_play.gd``net_world.gd``game_scene.gd``player_controller.gd``entity_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.cpp`OnMove/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.h`Android 需关掉 `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.py``prototype.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.2`ANDROID_NDK_HOME` 指向它;未设置时脚本选版本号最低的 NDK)、openjdk@21、Godot 导出模板;
`adb``/opt/homebrew/bin/adb`。APK 导出用 `./export-android.sh`
- 真服账号、密码不写进仓库或 audit 账本。
新会话恢复工作:
```bash
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 节更新状态并提交。