Metin2 game client (P0–P11) + mobile asset pipeline
Networked client on the existing Godot 4.7 + libgr2 renderer:
- net: m2dev wire protocol (libsodium KX + XChaCha20), auth/select/game
phases, EntityStore world model, ~all GC/CG headers. char create/delete,
private shop / mall / cube, SHOP_GC_START_EX, guild, party (+ CG_PARTY_SET_STATE),
quests, dragon soul, refine, safebox, exchange.
- UI: in-game windows migrated 1:1 from the reference uiscript/root .py —
char status (/stat), inventory+equipment, select-item ([SELECT_ITEM] quest
token), system-option + game-option + ESC system menu, private-shop 39-grid,
party info board, shop tabs, atlas, minimap, quickbar, chat, …
- EterGrnLib polish: GR2 material blend/two-sided, LOD crossfade, motion-event
dispatch, contact shadow, ray-AABB picking, weapon grip pre-transform.
Portable asset IO (A1) — all extension/libgr2/formats/mtproto reads routed
through godot::FileAccess (res:// PCK works on iOS/Android); standalone-lib
*_path() kept for the non-Godot CTests. AssetResolver + PropertyRegistry
switched to a baked index (bake_asset_index.gd) instead of std::filesystem.
Mobile builds: build-{android,ios}.sh, export-android.sh, pack-assets.sh,
gen-debug-keystore.sh. Assets ship as a zip mounted at runtime by
project/asset_pack.gd (adb push now; HTTP download is a drop-in later).
ctest 10/10, 34 GDScript suites, macOS/iOS/Android all build.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EJxkHiNKS4kybHS3XKyAJ
This commit is contained in:
@@ -1,19 +1,28 @@
|
||||
# mtgodot-poc
|
||||
|
||||
「**Godot 4 + 自研资源 loader**」跨平台方案的渲染 Demo(route ①)。
|
||||
用一个 C++ GDExtension 复用 [`xrender-poc`](../xrender-poc) 的 `libgr2`,把 Metin2 的
|
||||
`.gr2` 骨骼资源渲染进 Godot,用 Godot 内置渲染器。
|
||||
「**Godot 4 + 自研资源 loader**」跨平台方案的渲染 Demo。
|
||||
用一个 C++ GDExtension 把 Metin2 的 `.gr2` 骨骼资源渲染进 Godot,用 Godot 内置渲染器。
|
||||
|
||||
与 `xrender-poc`(自研引擎 + bgfx RHI)是**两条并行的跨平台基座候选**,共用 `libgr2`。
|
||||
> **2026-08-29:并入 `xrender-poc`。** 原先与本仓库并行的 bgfx 自研引擎方案(`xrender-poc`)
|
||||
> 经中期评审([`docs/MIDREVIEW.md`](docs/MIDREVIEW.md))**停止开发**,其可复用部分——
|
||||
> `libgr2`(gr2 v6/v7 读取器,已对拍 Granny)、`formats`(.msa/.msm)、`oracle`(Granny 真值工具)、
|
||||
> `tools`(libgr2 校验工具)、`docs/reference`(格式逆向笔记)——已 **vendored 进本仓库**。
|
||||
> bgfx 侧的渲染器 / 平台壳 / 第三方库全部弃用(Godot 取代)。bgfx demo 的参考截图留在
|
||||
> `test/bgfx-reference/` 供交叉核对。`xrender-poc` 目录本身已删除(2026-08-30)。
|
||||
|
||||
判定分两阶段:
|
||||
自用项目(内部研究,不对外发布),分两阶段推进:
|
||||
|
||||
| 阶段 | 平台 | 里程碑 | 产出 |
|
||||
|---|---|---|---|
|
||||
| **Phase 1**(当前) | macOS | M0' · M1 · M2 · M2.5 | 中期评审(不下 go/no-go) |
|
||||
| Phase 2 | iOS · Android | M3 | go / no-go |
|
||||
| **Phase 1**(当前) | macOS | M0' · M1 · M2 · M2.5 | 中期评审 |
|
||||
| Phase 2 | Android(一加 13 / Vulkan)· iOS(iPhone 16 / Metal) | M3 | 三设备各一次 bring-up + 性能留档 |
|
||||
|
||||
完整计划见 [`docs/GODOT-POC-PLAN.md`](docs/GODOT-POC-PLAN.md)。
|
||||
自用、不对外发布,**无正式 go/no-go 门禁**;三台目标设备都是现代硬件,**全程不涉及 GLES3 / Compatibility 渲染器**,不做中低端 / 老机器。
|
||||
|
||||
完整计划见 [`docs/GODOT-POC-PLAN.md`](docs/GODOT-POC-PLAN.md);离可用客户端还差什么见
|
||||
[`docs/BACKLOG.md`](docs/BACKLOG.md)(分层未完成清单);把参考图那种整张地图画面做出来的实施规格见
|
||||
[`docs/SHINSOO-WORLD-RENDERING.md`](docs/SHINSOO-WORLD-RENDERING.md)(正式移植,Phase 2 bring-up 之后);
|
||||
距参考图「目视等价」还差哪些保真化工作见 [`docs/PARITY-GAP.md`](docs/PARITY-GAP.md)。
|
||||
|
||||
---
|
||||
|
||||
@@ -26,18 +35,26 @@
|
||||
(`test/golden/m1-bindpose.png`)。多骨架:`warrior_lord`(v6,74)、`assassin`(v6,95,17 表面)、
|
||||
`shaman_lord`(**v7**,93) 均正确加载渲染。
|
||||
- [x] **M2** — 骨骼动画。`Metin2AnimPlayer` `_process` 里 `gr2::sample_pose`(跨文件)
|
||||
→ 逐骨 `Skeleton3D.set_bone_pose`(局部),Godot GPU 蒙皮。`general/wait` 头 / 护甲
|
||||
对齐正确(`test/golden/m2-wait.png`);`get_bone_global_pose` vs `conv(world)` 全骨 ≤2.6e-5;
|
||||
CPU-LBS 参考路径(`MTGODOT_CPUSKIN=1`)与 GPU 蒙皮一致;`selfcheck` 0 NaN。
|
||||
⚠️ `dance_1` 等表情动作头 / 颈塌陷 —— **libgr2 曲线解码 bug,xrender-poc bgfx demo 同样复现**
|
||||
(见 `docs/MIDREVIEW.md` §4)。
|
||||
- [~] **M2.5** — 材质与观感保真。`ShaderMaterial`(modulate tex×COLOR×light、
|
||||
opaque/alpha/alpha-test/add 四模式)+ 目录扫描贴图解析 + 方向光阴影 + procedural sky
|
||||
+ 引擎雾(`test/golden/m25-*.png`)。**门禁未闭**:多材质槽 → 贴图/混合的精确映射需
|
||||
给 libgr2 加材质 API(见 `docs/GODOT-POC-PLAN.md` §M2.5 T2.5.6 差距清单)。
|
||||
→ **默认 CPU 线性混合蒙皮**(把 libgr2 的 `Σ w·invWorld·world` 直接作用到顶点,每帧重建 mesh)。
|
||||
`get_bone_global_pose` vs `conv(world)` 全骨 ≤2.6e-5;`selfcheck` 0 NaN;`dance_1` 等所有动作
|
||||
头/护甲/躯干正确,与 xrender-poc bgfx demo 一致。
|
||||
`MTGODOT_GPUSKIN=1` 走**自写蒙皮顶点着色器**(`m2_material` `SRC_SKIN`:逐骨完整 4×3 矩阵
|
||||
存 RGBAF 纹理,绕过 `Skeleton3D` —— Godot 内置 GPU 蒙皮会正交化、丢 Granny 烘在 rig 骨上的
|
||||
shear,warrior 7 根 / **sura 16 根**,见 `test/shear-bones-survey.md`)。人群场景用它。
|
||||
**`.msa`**:`anim_path` 收 `.msa` → motion `.gr2` + `Accumulation` + `MotionEventData`
|
||||
(`get_events()` / `motion_event` 信号,带循环回绕)+ `LoopData` 元数据;播放器 `loop=false`
|
||||
可播一次并发 `playback_finished`(片段循环次数执行仍在 backlog C4)。
|
||||
**`.msm`**:`gr2_path` 收 `.msm` → 自动加载 `BaseModelFileName`(含散包目录扫描)+
|
||||
`get_hair_options()` 发型目录(发型 mesh 挂接留 Phase 2)。
|
||||
- [x] **M2.5** — 材质与观感保真。`ShaderMaterial`(modulate tex×COLOR×light、
|
||||
opaque/alpha/alpha-test/add 四模式)+ 方向光阴影 + procedural sky + 引擎雾。
|
||||
**贴图走 gr2 material 绑定**:`build_parts()` 按 `tri_groups[].material_index` 把一个 gr2 mesh
|
||||
拆成多个 Godot surface,各 surface 取 `Mesh::material_textures[matidx]`(mesh-local)→
|
||||
同目录大小写不敏感查 `.dds`;找不到才回退文件名启发式。shaman(1→2 面)/assassin(17→18 面)
|
||||
各面贴图正确。MODULATE2X 等 stage op 仍只近似(差距清单见 `docs/GODOT-POC-PLAN.md` §M2.5 T2.5.6)。
|
||||
- [~] **中期评审** — [`docs/MIDREVIEW.md`](docs/MIDREVIEW.md)。结论:桥接层工程量小、
|
||||
风险基本出清,**建议进入 Phase 2**。收尾 3 项:`compare.py` 对拍、`dump_materials`
|
||||
Granny 对拍闭合 M2.5 门禁、前台/真机性能重测。
|
||||
风险基本出清,**建议进入 Phase 2**。`compare.py` 已有进程/截图/结构硬门禁,像素差仍为
|
||||
advisory;收尾重点是前台/真机性能重测与桥接层全语料 draw 冒烟(默认已是 CPU LBS)。
|
||||
|
||||
50 角色压力采样:`test/godot-macos-stress.json`(后台窗口 30fps 节流,仅构建成本
|
||||
~165ms/角色 和 100 角色破顶到 52ms 是可信信号)。
|
||||
@@ -49,10 +66,10 @@
|
||||
| 组件 | 版本 / 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| Godot | **4.7.1**(`/opt/homebrew/bin/godot`,Homebrew cask) | 编辑器 + headless |
|
||||
| godot-cpp | submodule `extension/godot-cpp` @ `master`(pin `101ae38`) | master 默认 targets Godot 4.7 API(`GODOTCPP_DEFAULT_API_VERSION=4.7`);无 `4.6/4.7` 分支,只有 bundled `extension_api-4-7.json` |
|
||||
| godot-cpp | submodule `extension/godot-cpp` @ `101ae38034304346a46ea9ea84ae156d3e860496` | 精确 gitlink 锁定(`.gitmodules` 不跟踪移动分支);bundled `extension_api-4-7.json` |
|
||||
| Xcode | 26.4.1 | macOS 构建 |
|
||||
| CMake | 已装;**不需要 SCons** | godot-cpp 走 CMake 路径 |
|
||||
| libgr2 | `../xrender-poc/libgr2`(sibling-dir 引用) | 见下「libgr2 依赖」 |
|
||||
| libgr2 / formats / oracle / tools | vendored 进本仓库 | 见下「vendored 库」 |
|
||||
|
||||
**导出模板**(M0' T0.4 / 真正 export 才需要):编辑器内 `Editor → Manage Export Templates → Download`,或 `godot --headless --install-export-templates`。~600MB,版本须与编辑器一致(4.7.1)。
|
||||
|
||||
@@ -66,19 +83,38 @@ git submodule update --init --recursive # 拉 godot-cpp(首次)
|
||||
./build.sh Release # template_release
|
||||
```
|
||||
|
||||
首次会编译 godot-cpp(几分钟)。
|
||||
首次会编译 godot-cpp(几分钟)。扩展构建自动带上 vendored `libgr2` + `formats`。
|
||||
|
||||
只想构建 `libgr2` / `formats` / 校验工具(不碰 godot-cpp):
|
||||
|
||||
```bash
|
||||
cmake -B build-tools -DMTGODOT_BUILD_EXTENSION=OFF -DMTGODOT_BUILD_TOOLS=ON
|
||||
cmake --build build-tools -j8
|
||||
./build-tools/tools/gr2fuzz "$PWD/assets" # 全量解析冒烟
|
||||
./build-tools/tools/gr2dump <file.gr2>
|
||||
```
|
||||
|
||||
## 运行
|
||||
|
||||
```bash
|
||||
# 完整客户端:登录 → 选人 → 进游戏(用仓库内 assets/)
|
||||
./run-client.command # 或双击
|
||||
# = MT_ASSETS=$PWD/assets godot --path project res://client_main.tscn
|
||||
|
||||
# 打包 .app(需先装 Godot 4.7.1 macOS 导出模板)
|
||||
./build-macos-client.sh [debug|release] # -> build/export/mtgodot-poc.app
|
||||
|
||||
# 编辑器打开
|
||||
godot -e --path project
|
||||
|
||||
# 模型查看器 harness(旧 main_scene)
|
||||
godot --path project res://main.tscn
|
||||
|
||||
# headless 冒烟测试(验证 GDExtension 加载 + 类注册)
|
||||
godot --headless --path project --quit-after 3
|
||||
|
||||
# 跑一个真实 gr2 过 libgr2(可选)
|
||||
MTGODOT_PROBE_GR2="$PWD/../m2dev-client-main/assets/PC/ymir work/pc/warrior/warrior_cheongrin.gr2" \
|
||||
MTGODOT_PROBE_GR2="$PWD/assets/PC/ymir work/pc/warrior/warrior_cheongrin.gr2" \
|
||||
godot --headless --path project --quit-after 3
|
||||
```
|
||||
|
||||
@@ -88,22 +124,23 @@ MTGODOT_PROBE_GR2="$PWD/../m2dev-client-main/assets/PC/ymir work/pc/warrior/warr
|
||||
|
||||
---
|
||||
|
||||
## libgr2 依赖
|
||||
## vendored 库(并入自 xrender-poc,2026-08-29)
|
||||
|
||||
M0' 直接用 **sibling-directory 引用**:`extension/CMakeLists.txt` 里
|
||||
`XRENDER_POC_DIR` 默认 `../../xrender-poc`,`add_subdirectory` 进 `libgr2`。
|
||||
两个 repo 都在 `.../mt/` 下时开箱即用。
|
||||
| 目录 | 内容 | 谁用 |
|
||||
|---|---|---|
|
||||
| `libgr2/` | gr2 v6/v7 只读读取器(header/section/Oodle1/类型树/骨架/网格/曲线/材质)。零第三方依赖。9166 语料 fuzz 0 崩溃;bind pose + 蒙皮对拍 Granny 2.9.12 ≤6.5e-5。含 `dump_materials()`。 | `extension`(`xrender::libgr2`)、`tools` |
|
||||
| `formats/` | `.msa`(动作)/ `.msm`(模型 + 发型)/ textscript 解析。 | M2 T2.2/T2.3 起(retarget + motion event) |
|
||||
| `oracle/` | Wine + MinGW 交叉编译的 Granny 真值工具(`oracle.c` + 脚本 + `RUNBOOK.md`)。`oracle.exe` / `granny2_x64.dll` 不入库(体积 + RAD IP),`build-wine.sh` 本地重建。 | M2 数值门禁、M2.5 材质对拍 |
|
||||
| `tools/` | `gr2dump`(转储)/ `gr2fuzz`(全量解析冒烟)/ `oracle_diff`(libgr2 vs oracle 逐字段对拍)/ `anim_probe`(每骨 world 3×3 的 det/shear/scale 探针,查蒙皮走样)。 | libgr2 回归 |
|
||||
| `docs/reference/` | xrender-poc 的格式逆向笔记(M0–M4 施工文档 + PLAN)。见 `docs/reference/README.md`。 | 查格式细节 |
|
||||
| `test/bgfx-reference/` | bgfx demo 的参考截图 + `noise_floor.json` / `m2-numeric.json` / `assets.list` 基线。 | 与 Godot 输出交叉核对 |
|
||||
|
||||
换机 / CI 时二选一:
|
||||
- `git submodule add <xrender-poc url> third_party/xrender-poc` 后传 `-DXRENDER_POC_DIR=third_party/xrender-poc`
|
||||
- vendor 一份 `libgr2/` 进本仓库
|
||||
CMake:顶层 `add_subdirectory(libgr2)` + `add_subdirectory(formats)`(跨平台,不碰 godot-cpp);
|
||||
`extension` 只 `target_link_libraries(... xrender::libgr2)`。`tools` 由
|
||||
`-DMTGODOT_BUILD_TOOLS=ON` 开启。
|
||||
|
||||
> ⚠️ 本仓库依赖 `../xrender-poc/libgr2` 里新增的 `dump_materials()`
|
||||
> (`src/gr2_material.cpp` + `include/gr2/gr2.h` + `CMakeLists.txt` 三处,纯附加)。
|
||||
> 该改动目前只在 xrender-poc 工作树里,**未提交**(那个仓库无提交历史,保持原样)。
|
||||
> 需要时由 xrender-poc 的维护者按其流程纳入。
|
||||
|
||||
`formats/`(msa/msm)到 **M2** 才需要,届时同样方式接入。
|
||||
> `libgr2/README.md` 里的 **oodle1.c clean-room 提醒**依然适用:`src/oodle1.c` 是泄露 SDK 端口,
|
||||
> 仅限内部研究 / 非发布 / 非商用;对外发布前必须 clean-room 重写。
|
||||
|
||||
---
|
||||
|
||||
@@ -111,27 +148,42 @@ M0' 直接用 **sibling-directory 引用**:`extension/CMakeLists.txt` 里
|
||||
|
||||
```
|
||||
mtgodot-poc/
|
||||
CMakeLists.txt 顶层(macOS only 守卫)
|
||||
build.sh 便捷构建
|
||||
CMakeLists.txt 顶层:add_subdirectory(libgr2/formats/[tools]/[extension])
|
||||
build.sh 便捷构建(扩展)
|
||||
libgr2/ ← vendored:gr2 读取器(xrender::libgr2)
|
||||
formats/ ← vendored:msa/msm/textscript
|
||||
oracle/ ← vendored:Granny 真值工具(exe/dll 不入库)
|
||||
tools/ ← vendored:gr2dump / gr2fuzz / oracle_diff
|
||||
extension/
|
||||
CMakeLists.txt mtgodot SHARED + godot-cpp + libgr2
|
||||
godot-cpp/ submodule @ master
|
||||
CMakeLists.txt mtgodot SHARED + godot-cpp(consume xrender::libgr2)
|
||||
godot-cpp/ submodule @ 101ae38034304346a46ea9ea84ae156d3e860496
|
||||
src/
|
||||
register_types.{h,cpp} GDExtension 入口,注册 Metin2Model
|
||||
metin2_model.{h,cpp} M0' 占位节点(证明类注册 + libgr2 链接)
|
||||
register_types.{h,cpp} GDExtension 入口
|
||||
metin2_model.{h,cpp} gr2 → Skeleton3D + ArrayMesh + Skin + 材质
|
||||
metin2_anim.{h,cpp} 每帧 sample_pose → Skeleton3D;selfcheck
|
||||
gr2_bridge.{h,cpp} libgr2 POD → Godot 类型;basis + 单位换算
|
||||
m2_material.{h,cpp} Metin2 风格 ShaderMaterial(mix / add)
|
||||
dxt.{h,cpp} DDS DXT1/3/5 软解
|
||||
assets/ Metin2 资产(.gr2/.dds/locale/OutdoorA1/…,gitignored;换位置设 MT_ASSETS)
|
||||
bgm/ 背景音乐(assets/ 同级,gitignored)
|
||||
project/ Godot 4.7 工程
|
||||
project.godot
|
||||
main.tscn 根 Node3D + main.gd
|
||||
main.gd M0' harness:建 env/light/cam/cube + 探测扩展
|
||||
assets/.gdignore 让 Godot 不 import .gr2/.dds
|
||||
bin/mtgodot.gdextension 扩展描述符(dylib 构建产物落这里)
|
||||
export_presets.cfg macOS preset
|
||||
client_main.tscn/.gd 完整客户端入口(main_scene)→ AppFlow 登录串场
|
||||
app_flow.gd LOGIN → SELECT → GAME 状态机
|
||||
main.tscn / main.gd 旧模型查看器 harness
|
||||
asset_root.gd AssetRoot:资源目录解析(MT_ASSETS / res://../assets / .app 内外)
|
||||
docs/
|
||||
GODOT-POC-PLAN.md 开发计划(M0'–M4 + 风险 + 验收)
|
||||
steps/ (按需)
|
||||
test/golden/ 对拍截图(M1 起)
|
||||
MIDREVIEW.md Phase 1 中期评审
|
||||
BACKLOG.md 离可用客户端的分层未完成清单
|
||||
reference/ ← xrender-poc 的格式逆向笔记(archived)
|
||||
test/
|
||||
golden/ Godot 对拍截图
|
||||
bgfx-reference/ bgfx demo 参考截图 + 数值基线
|
||||
*.json noise_floor / m2-numeric / stress
|
||||
```
|
||||
|
||||
## 授权
|
||||
|
||||
`libgr2` 全自研,不含 Granny SDK 代码。本仓库内部研究用途,不对外公开。
|
||||
`libgr2` 全自研,不含 Granny SDK 代码 —— 例外:`libgr2/src/oodle1.c` 是泄露 SDK 的解码路径端口
|
||||
(见 `libgr2/README.md`,仅限内部研究 / 非发布,对外发布前必须 clean-room 重写)。
|
||||
本仓库内部研究用途,不对外公开。
|
||||
|
||||
Reference in New Issue
Block a user