Files
mtgodot-poc/docs/reference/steps/M3-mobile.md
T
shenandClaude Sonnet 5 47baf6c0c6 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
2026-08-31 20:02:12 +09:00

8.7 KiB
Raw Blame History

M3 · iOS + Android 真机

总纲:../PLAN.md §04 / §06 / §07。 本文件是 M3 的详细施工文档。与 M2 尾段并行。


目标

M2 的工程原样交叉编译到 iOS + Android 真机跑基准场景, 证明三端渲染一致、移动端性能达标、生命周期(context loss / 后台)稳。

前置

  • M2 门禁 1–2 通过(骨骼矩阵 + 蒙皮顶点对拍)。
  • M1 T0b 的交接结论(决定移动端窗口壳用什么)。
  • 资产上真机的方案(见下 T1)—— 不是"原样交叉编译"就完事。

交付物

产物 位置
iOS .appXcode / CMake iOS toolchain platform/ios/
Android APKNDK / Gradle 或纯 CMake + native_app_glue platform/android/
三端 CImacOS 原生 + iOS 模拟器 + Android 模拟器) .github/ 或等价
真机性能采集报告 test/m3-perf.json
三端快照互拍报告 test/m3-snapshot.json

任务分解

T1 · 资产上真机方案(PLAN §04 / §08)

  • 9166 个散装 .gr2 + .dds 不能直接堆进 APK / .bundle(体积、iOS 限制)。二选一:
    • A(推荐)M3 前提前接 EterPack(现排 M4),资产走 .eix/.epkCMappedFile 的 mmap / AAsset_getBuffer 路径。
    • B(最小):只把 test/assets.list 里那 ~15 个 + 依赖贴图打进去。
  • 完成判据:真机上 libgr2 能加载 warrior + dance_1,路径与桌面散文件结果一致。

T2 · 平台壳

  • 窗口 / 生命周期:按 M1 T0b 结论——sokol_app(若交接成了)或各平台最小原生壳(iOS MTKView + CADisplayLinkAndroid NativeActivity / GLSurfaceView)。
  • iOS:全静态链接(无 dlopen);.bundle 打包资产;Info.plist / 签名走开发证书(不涉及上架)。
  • AndroidNDK arm64-v8a + armeabi-v7aAAssetManager 经 JNI 注入(复用 MobileSource AndroidMain.cpp 形态)。
  • bgfx init.typeiOS = MetalAndroid = OpenGLES(或 Vulkan,先 GLES3 稳)。

T3 · Android context lossPLAN §08 高危,确定项)

  • 切后台 → GL context 连同 GPU 资源可能失效。
  • SUSPENDED / RESUMED(或 onSurfaceDestroyed/Created)里按 bgfx 的重置流程:bgfx::reset + 必要时重建 sg_* / bgfx 资源句柄。
  • 测试:切后台 ×100adb shell input keyevent KEYCODE_HOME + 回前台脚本循环)。
  • 完成判据100 次无崩、无黑屏、无资源泄漏(adb shell dumpsys meminfo 稳定)。

T4 · iOS 后台 / drawable 生命周期(PLAN §10.1

  • 切后台 / 锁屏 / 来电 → 丢 CAMetalDrawable
  • applicationWillResignActive 暂停渲染循环;didBecomeActive 恢复;nextDrawable 返回 nil 时跳过该帧不崩。
  • 完成判据:后台 / 锁屏 / 来电各 ×20 恢复正常。

T5 · mediump 精度专项(PLAN §08 / §10.1

  • 移动 GPU 上 mediump 存不下 60 骨链的骨骼矩阵 / 大坐标 → 抖动 / 爆顶点。
  • 顶点着色器里骨骼矩阵与位置强制 highp;必要时把模型原点归一(减去包围盒中心)。
  • 测试:highp 前后对比截图,确认抖动 / 爆顶点消失。
  • 完成判据highp 版无可见抖动。

T6 · 性能采集(PLAN §07 性能层)

  • 基准硬件写死具体机型iPhone 11A13+ Pixel 6Mali-G78+ 一台 Adreno 机。
  • 两种角色:① 简化(≈5k 三角、≈60 骨、单 draw call);② 满配(多部件 + 武器 + 时装 + 挂点特效,1–2 万三角、多 draw call)。每种 1 → 8 → 20 → 50 个。
  • 指标:帧时间 p50/p99、FPS、draw call、GPU 显存(Xcode GPU report / Android GPU Inspector / adb dumpsys meminfo)、冷启动到首帧、单 .gr2 加载耗时、峰值 RSS。
  • 写进 test/m3-perf.json,逐项标注是否越线。

T7 · 三端快照互拍 + CI

  • 确定性场景在 macOS / iOS / Android 各渲一帧,两两 SSIM。
  • 三端之间应比各自与 oracle 更接近(同 shaderc 源、同逻辑)。
  • CIiOS 模拟器 + Android 模拟器构建并启动,断言"到达首帧 + 连续 N 帧无 bgfx / Metal / GLES 验证层报错"(开 BGFX_DEBUG_*、Metal API validation、GLES KHR_debug)。

门禁(go / no-go

  • 三端渲染差异分类通过(不是"逐像素一致",见 PLAN §07 视觉层:SSIM ≥ 0.98 直接过;0.950.98 进分类;< 0.95 fail)。
  • 性能:简化角色 1 个 ≥ 60fps、20 个 ≥ 30fps满配角色 1 个 ≥ 60fps、8 个 ≥ 30fps;冷启动 < 3s;基准 RSS < 300MB;单角色加载 < 30ms。
  • 无 bgfx / 图形验证层报错。
  • Android 切后台 ×100 恢复正常iOS 后台 / 锁屏 / 来电恢复正常
  • mediump 精度专项通过highp 后无抖动)。

验证

  • 三端快照互拍矩阵(T7)。
  • 真机性能逐项对通过线(T6)。
  • 生命周期压力测试脚本可复现(T3 / T4)。

本步风险(从 PLAN §08 筛)

风险 缓解
Android GL context 丢失后 GPU 资源需重建(确定项) T3 在 suspend/resume 走 bgfx resetM3 就做别拖
iOS 全静态 + 后台丢 drawable T2/T4 全静态链接 + drawable nil 跳帧
9166 散装资产上真机方式没定 T1 二选一,M3 交付显式包含
移动 GPU mediump 精度不足 T5 骨骼矩阵 / 位置用 highp
shaderc 跨编译 metal / 300_es 行为差异 单一 .sc 源;开验证层;T7 三端快照对拍
深度范围 / Y 翻转后端差异 bgfx::getCaps()->homogeneousDepth / originBottomLeft 抹平
sokol_app 交接在 iOS/Android 也不成 用各平台最小原生壳(T2 备选)

DoD 清单

  • [~] iOS 模拟器跑起来,播 dance_1CPU 蒙皮 + bgfx Metal,输出与 macOS 同 t 像素级一致(同 .bin 着色器、同 demo_core)。test/golden/m3-ios-*.png真机(差异分类、后台/锁屏/来电、mediump、perf)待设备。
  • Android 真机 —— 脚手架就绪(platform/android/)未构建:本机无 NDK。
  • test/m3-perf.json —— 待真机
  • Android 切后台 ×100 —— 待设备(android_main.cppAPP_CMD_TERM/INIT_WINDOW 分支已写 shutdown/reinit
  • iOS 后台 / 锁屏 / 来电 —— 待设备(ios_main.mmapplicationWillResignActive/DidBecomeActive 暂停/恢复 CADisplayLink 已写)
  • mediump → highp 专项 —— vs_pnt_skinned.sc 已写(骨骼矩阵 + 位置全 highp);对比测试待真机 GPU
  • CI 三端 job —— 待
  • M3 全绿 = PLAN §01 判定"方案可行" —— iOS 一端已验证(编译 + 运行 + 渲染一致);Android 端 + 真机压测待设备

M3 实现结果(本轮)

结果
平台无关核心 app/demo_core.{h,cpp} —— 加载 gr2 + 建场景 + 采样姿势 + 画,无窗口/输入依赖。桌面壳(app/main.cpp GLFW+ iOS 壳(platform/ios/ios_main.mm UIKit+ Android 壳(platform/android/android_main.cpp native_app_glue)都调它。
iOS 壳(T2 ios_main.mmUIApplicationMainMetalView+layerClass = CAMetalLayer)→ CADisplayLinkdemo::frame。bgfx nwh = CAMetalLayer*init.type = Metal。生命周期回调(T4 骨架)已接。
iOS 构建 + 运行 cmake -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphonesimulatorBUILD SUCCEEDEDxcrun simctl 装 + 跑 iPhone 16 Pro 模拟器:libgr2 加载 warrior + dance_1、DXT3/DXT1 解码、bgfx Metal init、CADisplayLink 跑 120 帧无崩、requestScreenShot 出图。渲染结果与桌面同 t 一致。
交叉编译坑 BGFX_CONFIG_VIDEO 默认 ONvideo_mtl.cpp 在 iOS 模拟器编不过(CVMetalTextureCache 不可用)→ 关掉。② shaderc 跑不了目标平台 → xrender_compile_shaders(... PREBUILT <dir>) 用宿主机预编译的 metal .binMetal 字节码 macOS/iOS 通用)。③ iOS 不建 GLFWthird_party/CMakeLists.txtNOT IOS 守卫)。
Android 壳(T2 platform/android/android_main.cppnative_app_glue + ANativeWindow → bgfx GLES nwh + AAssetManager 解资产)、CMakeLists.txtNDK,链 xr_democore + bgfx GLES)、build.gradle + AndroidManifest.xmlNativeActivity)。未构建(本机无 NDKplatform/android/README.md 记了装 NDK 后的步骤)。
T5 GPU 蒙皮 shader app/shaders/vs_pnt_skinned.scu_bones[64] 混合,骨骼矩阵 + 位置 + 法线全 highp未接进 demodemo 走 CPU 蒙皮 = M2 数值门禁路径),留 M4 CPU/GPU 一致性 + 真机 mediump 对比。