# Android 相机、MMD 与设置整合(2026-10-01) 开发分支:`dev/android-main-bem-import-20260927`。本轮将 `main@3b285742` 合入安卓分支,保留安卓渲染线程控制、JNI ClassLoader 隔离、Hook 所有权与 BEM 打开方式导入。 ## 功能与使用 - 悬浮窗左侧纵向切换 HUD、自由相机、冻结、第一人称与 MMD;内容独立滚动,按屏幕安全区域限制宽高。自由相机速度、FOV 使用滑条。 - 收起保留控制点;“本次关闭”隐藏整个悬浮窗,Activity 恢复或重建不重新显示,游戏进程重启后重新按配置显示。关闭会释放按住的输入,保留已启动功能;进入后台时在 Unity 帧上停止播放、退出相机并恢复冻结。 - 时间冻结独立于自由相机。切换相机模式保留冻结,关闭冻结功能或进入后台才恢复模块捕获的原时间倍率。 - 第一人称共享 PC 的头发名称扩展、多 Renderer 扫描、独立头发隐藏和水平侧看后的平滑转身。默认侧看上限 90°、转身速度 360°/秒,可在安卓相机页调整。 - MMD 作品页通过系统目录选择器导入包含 `set.ini` 的目录。动作、表情、镜头、音乐及多人文件沿用 PC 的作品格式。先发布全部不可变文件,再发布作品索引;游戏启动前复制到自己的私有目录。 - MMD 悬浮窗有作品选择、播放/暂停/停止、时间轴、前后跳转、循环、镜头模式和机位管理。关键帧默认保存到游戏私有 `betterendfield/camera-path.becam`。 - 高级设置提供身体/表情、动作比例、衣物物理、地形贴合选项及 orbit/dollyzoom/crane/truck 运镜、平滑、速度、目标高度、持续时间、关键帧时长和循环。 - 同一角色可以安装多个 BEM 包;启用一个会停用同角色其他包。转换只替换目标 generation,移除不影响其他有效包。组件/外观选项收入展开区并即时保存。 - 设置页取消手动保存。开关、选项立即保存;文本 450ms 防抖并在离页时刷新,无效输入保留上次有效值。模块装载和导入文件需要重启游戏;游戏内控制立即执行。 ## 布局与接口回退 原共享 UI 在 `mobile_ui_enabled=false` 且没有恢复值时,会把输入类型默认为 Keyboard。安卓只开启 HUD/UID 也可能走该路径。本轮修复为默认不切换任何布局;只有显式启用 PC 布局才调用 `DeviceInfo.ChangeInputType` 并通知 `UIStyleByState`。Keyboard 枚举通过元数据取值,缺少契约则保留原布局。关闭时恢复进入前的 Touch/Controller 模式,不改账号平台声明。 issue #18 报告某个 realme 样本缺少 `il2cpp_domain_get_assemblies`;用户的小米设备并不是该失败样本。品牌不是已确定根因。本轮将程序集枚举与 image 名称查询设为可选;对应导出缺失时使用已经解析的 `il2cpp_domain_assembly_open` 按名字查询,兼容带/不带 `.dll` 名称。正常导出可用时保留原枚举路径,不猜测地址或扫描隐藏符号。 详见 [issue 与资源来源记录](../../../../android/research/1.5.3/resource-sync/ANDROID_RESOURCE_SYNC.md)。手机上的回退测试使用模拟缺失接口,不意味着该手机实际缺少接口。 ## 平台适配边界 MMD director、VMD 相机与路径文件读写直接共享 PC 实现;安卓用有界命令队列和 JSON 状态代替 Windows 共享内存与伴随窗口。JNI 只提交控制请求,Unity 对象操作在已经观察到的帧线程执行。 EIEM 原 PC 的 Windows/SEH 和原生对象布局不能直接用于 ARM64。安卓适配复用 EIEM 的解析、采样与 DirectVmd 数学,用托管接口绑定角色、FK/扭转骨、腿部求解、表情和衣物状态。具体能力依赖对应客户端元数据,缺失只禁用该能力并记录日志;不能把编译或离线测试当作实际舞蹈、布料效果验收。Camera 与 Actions 共享同一姿态租约,避免同时写同一骨架。 安卓本地音轨通过 MediaPlayer 实现相同 `BE_LocalMusicApiV1` 时间轴接口;准备、播放、暂停、跳转与状态采集在媒体线程执行。音量范围 0–1。这不是 PC 的 Wwise/OmniMix 排他通道,会叠加游戏 BGM,作品页提示用户关闭游戏背景音乐。媒体代次检查与状态发布串行,旧回调不能覆盖新作品的状态。 地形跟随通过 `ComputeFloorDist` / `FindFloor` 及实际分配并固定的托管 `FindFloorResult` 调用,按字段/方法名称读取命中、可行走面、高度和法线;不使用 PC 的结果缓冲区尺寸或字段偏移。每个角色共享 EIEM 的地形平面、根高度和脚趾求解数学,镜头引用包含地形高度偏移。暂停保持地形状态,跳转重置状态;接口缺失或托管异常只关闭地形,在 MMD 悬浮窗显示原因,普通动作和相机继续。 ## 资源更新 从用户授权的无线调试手机定点读取当前 Android VFS、manifest、AudioDialog、必要 PrefabInfo 与四语言头部/BNK。模型/动作记录仍为 32 模型、4,210 动作,保留 Android 专属哈希并更新 manifestHash。语音目录从 132 增至 136,噗切娜四语言齐全,原目录与路由全部保留。没有删除旧快照或搬运完整客户端。 当前安卓来源与校验证据见 `android/resources/resource-source.json`、`voice-index-android-evidence.json` 和资源同步报告。原 135 目录的历史合并记录仅作过程证据,最终目录已经使用完整当前安卓四语言来源生成。 ## 验证记录 - 安卓 Debug 和最终 3.4.0 Release(versionCode 30400)完整 APK 构建通过。Release 保留工程的 debug 签名配置,APK 签名校验通过;包内为 136 个四语言目录,数据与已验证安卓索引逐字节一致。 - Windows Camera、UI、Actions 和第一人称几何测试重新构建通过;几何测试通过。 - 用户授权无线调试设备(Android 17,ARM64)运行隔离测试:生产 runtime 的静态字段/枚举/程序集回退、输入队列与线程、模拟 Hook 所有权、相机暂停和 UI 布局恢复均通过。测试只调用夹具对象,未注入游戏。 - MMD 音频宿主 JVM 23 项检查通过,包括异步准备、连发跳转、旧 token/回调、关闭重开、异常和跨代状态竞争。 - BEM 67 项宿主状态检查通过;高级设置 80 项宿主断言和悬浮窗安全区域检查通过(子代理执行)。这些不等同于真实转换或 UI 实机验收。 - EIEM 四 slot 与 body 的 ARM64 NDK 语法检查通过;两组 owned-object 夹具验证自然绑定姿态、身体/手指/腿脚/扭转、SMC 和布料接管恢复、地形高度/暂停/错误回退、四人异步加载、停止后再播放与 GC 句柄释放。 Release 打包沿用现有 Gradle 工作目录;针对搬运后被设为只读的构建输出仅清除只读属性,没有删除项目或全量 clean。`RuntimeBootstrap.loadIntoTargetNamespace` 的非 SDK 调用仅对框架注入入口做局部 Lint 标注;被系统拒绝或接口不存在时仍由运行时记录失败并关闭,未对全项目关闭 Lint。 真实游戏中的多人动作、表情、布料、冻结恢复、第一人称残留头发及触屏/键鼠布局效果需单独测试。本轮不会将未执行的游戏验证写成通过。 ## 合并 main 前检查(2026-10-01) 远端 `main@3b285742` 是安卓开发分支的祖先,无独立新增提交,可快进合并且没有冲突。用户已检查外部页面,确认第三方模型在主界面切换可用。最终 APK 已通过 Release 构建、完整 `lintRelease`、签名检查及覆盖安装;PC 界面 Release 构建通过。 为检查安卓共享代码对桌面的影响,使用当前 `F:/Better Endfield/native` 源码,在本机 SSD 的 `D:/work/BetterEndfield-checks/main-merge-20261001` 构建 Windows Release 的 `BetterEndfield.Camera`、`BetterEndfield.Actions`、`BetterEndfield.UiModule`,全部通过。没有使用来源路径仍指向旧盘的 CMake 缓存,也没有清理或全量复制外置硬盘项目。Camera 的 shared_ptr 原子自由函数有 C++20 弃用提示;这是兼容 NDK libc++ 的现有写法,未影响编译。 本轮不重复已经通过且源码未变的宿主测试,不将编译或外部 UI 验收当作游戏内 MMD、物理及布局的效果验收。安卓 README 已同步压缩包/单项导入和主标签管理入口。