From 184b631ce85873fde33b3aa24bda5d453aa0ce70 Mon Sep 17 00:00:00 2001 From: shenlei Date: Tue, 22 Sep 2026 18:20:14 +0900 Subject: [PATCH] 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 --- AGENTS.md | 2 + CLAUDE.md | 2 + audit/remediation-roadmap.md | 4 +- docs/CLIENT-REFACTOR-40250-PLAN.md | 2 + docs/PORT-PLAN.md | 132 +++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 docs/PORT-PLAN.md diff --git a/AGENTS.md b/AGENTS.md index 5f15064f..40819a9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,3 +5,5 @@ When a task asks to compare, audit, implement, fix, or verify behavior against the Metin2 40250 client, read and follow `.agents/skills/metin2-40250-parity-audit/SKILL.md` before taking task actions. Treat `audit/manifest.json` as the persistent source of truth and update its evidence when parity work changes a conclusion. Do not load that specialized workflow for unrelated development tasks. + +The current port route, decisions and cross-machine setup are in `docs/PORT-PLAN.md`; read it first when resuming port work. diff --git a/CLAUDE.md b/CLAUDE.md index 79dc7ad6..4a323d25 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,3 +1,5 @@ # Project instructions For any Metin2 40250 comparison, 1:1 parity, missing original-client behavior, or parity-regression task, use the project skill `metin2-40250-parity-audit` from `.claude/skills/`. Keep audit state in `audit/manifest.json`; do not repeat still-valid verified work. + +The current port route, decisions and cross-machine setup are in `docs/PORT-PLAN.md`; read it first when resuming port work. diff --git a/audit/remediation-roadmap.md b/audit/remediation-roadmap.md index d43c4a8a..d1cd80ad 100644 --- a/audit/remediation-roadmap.md +++ b/audit/remediation-roadmap.md @@ -1,6 +1,6 @@ # 40250 1:1 移植队列 -工作方法见 `.agents/skills/metin2-40250-parity-audit/SKILL.md`。本文件只放批次和队列,不写每轮叙述(每轮结果记在 +路线与决定见 `docs/PORT-PLAN.md`,工作方法见 `.agents/skills/metin2-40250-parity-audit/SKILL.md`。本文件只放批次和队列,不写每轮叙述(每轮结果记在 `audit/port-map/**` 和 `audit/history.jsonl`)。2026-09-22 之前的按分支修复记录见本文件的 git 历史。 实时剩余量与下一批候选: @@ -17,7 +17,7 @@ python3 .agents/skills/metin2-40250-parity-audit/scripts/port_map.py queue --lim | 0 | 工具:参考根解析、缺失文件报错、`port_map.py`、构建/测试入口 | 完成 2026-09-22 | | 1 | 删除只被自身测试引用的 `project/*_system.gd` 与其 `test_*_parity.gd`,清除 manifest 中对应证据 | 完成 2026-09-22(106+106 个文件) | | 2 | P0 角色/移动单元,移植到 `extension/src/port//`(并行 worktree) | 未开始 | -| 2P | Python 层原型 2:CPython 2.7.18 静态编入 libmtgodot(macOS → Android → iOS),见 `docs/PYTHON-EMBED-EVAL.md` | 待确认 | +| 2P | CPython 2.7.18 静态编入 libmtgodot(macOS → Android APK → iOS),见 `docs/PYTHON-EMBED-EVAL.md` | 未开始(Android 独立程序已验证 b02c49bb) | | 3 | P1 战斗/技能 → P2 游戏阶段封包 → P3 物品;Python 层按 2P 的结论进行 | 未开始 | | 4 | `NEEDS_LIVE` 真服验证批 | 未开始 | diff --git a/docs/CLIENT-REFACTOR-40250-PLAN.md b/docs/CLIENT-REFACTOR-40250-PLAN.md index 935e3482..3e942789 100644 --- a/docs/CLIENT-REFACTOR-40250-PLAN.md +++ b/docs/CLIENT-REFACTOR-40250-PLAN.md @@ -1,3 +1,5 @@ +> **已取代(2026-09-22)**:现行路线见 `docs/PORT-PLAN.md`(逻辑层按 40250 文件结构照抄,UI 内嵌 CPython 2.7)。 + # 客户端重构与 40250 逻辑对齐实施方案 ## 1. 现状诊断与核心痛点 diff --git a/docs/PORT-PLAN.md b/docs/PORT-PLAN.md new file mode 100644 index 00000000..6fa40ee0 --- /dev/null +++ b/docs/PORT-PLAN.md @@ -0,0 +1,132 @@ +# 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//.{h,cpp}` | +| `python` | `root/*.py`、`uiscript/`、`UserInterface/*Module.cpp`、`EterPythonLib/`、`ScriptLib/` | 脚本原样运行;`*Module.cpp`、窗口系统、`CPythonLauncher` 照抄 | `extension/src/port//` + `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 编进 libmtgodot:macOS → 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` 和其他审计脚本。 +- Android:NDK 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 节更新状态并提交。