- GC_ITEM_DEL(20) 按 40250 旧结构为 42 字节,GC_REFINE_INFORMATION(95) 为 59 字节 - 公会标记连接接受 GC_MARK_DIFF_DATA(101),按 1 字节消费 - GUILD_SUBHEADER_GC_SKILL_INFO 服务器声明 22 字节但实际只写 21 字节, 按实际长度分帧,修复 "unknown GC header 200 (last: 75,20)" 断线 - 会话测试的 quest info 包改为 40250 按 flag 定长的格式,新增对应分帧测试 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ft3kXpNdLbKEfg5uDLfqVF
mtgodot-poc
「Godot 4 + 自研资源 loader」跨平台方案的渲染 Demo。
用一个 C++ GDExtension 把 Metin2 的 .gr2 骨骼资源渲染进 Godot,用 Godot 内置渲染器。
2026-08-29:并入
xrender-poc。 原先与本仓库并行的 bgfx 自研引擎方案(xrender-poc) 经中期评审(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 | 中期评审 |
| Phase 2 | Android(一加 13 / Vulkan)· iOS(iPhone 16 / Metal) | M3 | 三设备各一次 bring-up + 性能留档 |
自用、不对外发布,无正式 go/no-go 门禁;三台目标设备都是现代硬件,全程不涉及 GLES3 / Compatibility 渲染器,不做中低端 / 老机器。
完整计划见 docs/GODOT-POC-PLAN.md;离可用客户端还差什么见
docs/BACKLOG.md(分层未完成清单);把参考图那种整张地图画面做出来的实施规格见
docs/SHINSOO-WORLD-RENDERING.md(正式移植,Phase 2 bring-up 之后);
距参考图「目视等价」还差哪些保真化工作见 docs/PARITY-GAP.md。
当前进入游戏、模型/发型、贴地与技能栏问题的分阶段修复步骤,以及结合两个 Godot 项目的
对照验证和 macOS 包验收要求,见 docs/RENDERING-REPAIR-PLAN.md
(2026-09-08,实施计划;不表示其中工作已完成)。
现状
- M0' — 脚手架。GDExtension 加载 +
Metin2Model注册 +libgr2链接可调用- Godot 4.7 工程经 Metal Forward+ 出画。T0.4 实际
export待装 4.7.1 导出模板。
- Godot 4.7 工程经 Metal Forward+ 出画。T0.4 实际
- M1 — 静态渲染。
gr2→Skeleton3D+ArrayMesh+Skin+ 材质。warrior_cheongrin(75 骨 / 5 表面 / 3324 顶点)正立、朝 +Z、贴图正确 (test/golden/m1-bindpose.png)。多骨架:warrior_lord(v6,74)、assassin(v6,95,17 表面)、shaman_lord(v7,93) 均正确加载渲染。 - M2 — 骨骼动画。
Metin2AnimPlayer_process里gr2::sample_pose(跨文件) → 默认 CPU 线性混合蒙皮(把 libgr2 的Σ w·invWorld·world直接作用到顶点,每帧重建 mesh)。get_bone_global_posevsconv(world)全骨 ≤2.6e-5;selfcheck0 NaN;dance_1等所有动作 头/护甲/躯干正确,与 xrender-poc bgfx demo 一致。MTGODOT_GPUSKIN=1走自写蒙皮顶点着色器(m2_materialSRC_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)。 - 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。结论:桥接层工程量小、 风险基本出清,建议进入 Phase 2。compare.py已有进程/截图/结构硬门禁,像素差仍为 advisory;收尾重点是前台/真机性能重测与桥接层全语料 draw 冒烟(默认已是 CPU LBS)。
50 角色压力采样:test/godot-macos-stress.json(后台窗口 30fps 节流,仅构建成本
~165ms/角色 和 100 角色破顶到 52ms 是可信信号)。
环境
| 组件 | 版本 / 位置 | 说明 |
|---|---|---|
| Godot | 4.7.1(/opt/homebrew/bin/godot,Homebrew cask) |
编辑器 + headless |
| 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 / formats / oracle / tools | vendored 进本仓库 | 见下「vendored 库」 |
导出模板(M0' T0.4 / 真正 export 才需要):编辑器内 Editor → Manage Export Templates → Download,或 godot --headless --install-export-templates。~600MB,版本须与编辑器一致(4.7.1)。
构建
git submodule update --init --recursive # 拉 godot-cpp(首次)
./build.sh # Debug;产物 → project/bin/libmtgodot.macos.template_debug.dylib
./build.sh Release # template_release
首次会编译 godot-cpp(几分钟)。扩展构建自动带上 vendored libgr2 + formats。
只想构建 libgr2 / formats / 校验工具(不碰 godot-cpp):
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>
运行
# 完整客户端:登录 → 选人 → 进游戏(用仓库内 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/assets/PC/ymir work/pc/warrior/warrior_cheongrin.gr2" \
godot --headless --path project --quit-after 3
控制台出现 [mtgodot] Metin2Model registered OK — libgr2 linked; ... = M0' 的 T0.1/T0.2 通过。
窗口内:拖拽 = 轨道,滚轮 = 缩放,F2 = 截图(→ user://)。
vendored 库(并入自 xrender-poc,2026-08-29)
| 目录 | 内容 | 谁用 |
|---|---|---|
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 输出交叉核对 |
CMake:顶层 add_subdirectory(libgr2) + add_subdirectory(formats)(跨平台,不碰 godot-cpp);
extension 只 target_link_libraries(... xrender::libgr2)。tools 由
-DMTGODOT_BUILD_TOOLS=ON 开启。
libgr2/README.md里的 oodle1.c clean-room 提醒依然适用:src/oodle1.c是泄露 SDK 端口, 仅限内部研究 / 非发布 / 非商用;对外发布前必须 clean-room 重写。
目录
mtgodot-poc/
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(consume xrender::libgr2)
godot-cpp/ submodule @ 101ae38034304346a46ea9ea84ae156d3e860496
src/
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 工程
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 + 风险 + 验收)
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/src/oodle1.c 是泄露 SDK 的解码路径端口
(见 libgr2/README.md,仅限内部研究 / 非发布,对外发布前必须 clean-room 重写)。
本仓库内部研究用途,不对外公开。