NPC 反应动作表与 Godot 动作库
2026-09-20。本批补原模型 HIT / IDLE 资源、索引选择和实际播放接口。它是上一批 52CE50 分派器的模型端准备,不是普通 NPC 的 AI / 技能中断已经全部接通。
来源与覆盖
新增 tools/build_reaction_animations.py,扫描原怪物单位定义并沿继承链解析模型:
- 1114 个单位名映射到 343 个模型。
- 264 个模型的当前正常骨架载入路径可解析。
- 79 个模型保留 unverified 原因,不用目录文件名或 IDLE 回退补齐。
- 当前地图涉及的模型导出 30 份独立反应动作库。
- tools/rebuild_scenes.py 已接入生成步骤,可从源数据重建。
- 没有覆盖原地图的既有角色模型,新增库只向同一个 AnimationPlayer 提供动作。
主要未验证原因包括:48 个缺少模型同名清单、重复导入、源骨架文件不存在、源 XML 不完整等。数字是本次语料结果,不能当作全部 NPC 模型已支持。
原动画表不等于目录文件排序
对照 5A2440 / 5A14D0 / 598030 / 598790:
- 正常模型先加入基础骨架已有的动画,过滤星号开头的内部项。
- 再按 .ANIMATION 子块顺序载入 FILE 指向的骨架。
- 使用骨架文件里的实际动画名字;正常实体路径不能直接用清单 NAME 代替。
- 同基础骨架的 BIND 导入不凭空增加另一条索引。
- 当前未证明的多动画基础骨架顺序、重复导入覆盖等仍拒绝。
这条路径不是模型 +598 的特殊模式,也不覆盖外部骨架替换。清单保留 source hash、原名、索引、骨架时长、清单时长和 KEY 属性;尚未消费的 KEY 事件没有被删除后宣称完成。
ECHO PASS 受测 C_STURM_RANGED01_IMMOBILE 的真实表:
- index 12:HIT1,0.533333 秒;
- index 13:HIT2,0.533333 秒;
- index 14:IDLE,3.33333 秒。
选择规则
NativeModelAnimations 实现:
- 前缀存在性检查大写化请求,不消耗 RNG;
- 选择保留原表顺序,支持原大小写分支;
- 无候选返回 -1,不掷骰;
- 单候选仍做原浮点随机选择,推进两步 MWC;
- 使用 float 归一化权重、严格大于比较;
- 极少数权重总和略低于 1 时,保留原 index 0 回退,不能改成第一个前缀候选或安全异常。
例如 25 个等权条目、roll=.99999999 时可走 index 0 回退。该索引不保证属于 HIT 前缀。
这些索引仍在单位 527440 ANIMATION_ALTS 解析之前;显示端接收已经解析好的索引,不自行决定持武器变体。
严格导出与姿态边界
现有转换器新增显式 clip_sources 路径:
- 来源文件和骨架内部名字必须精确存在,不调用“缺失就 IDLE”的通用回退。
- 复用已有独立 TRS 时间流处理,不用其他骨骼的时间点进行 nearest-key 重采样。
- 保留缩放轨道。
- 合法的静止 IDLE(如训练假人)输出常量轨道,不输出无 channel 的无效 glTF 动画。
- 旧调用路径未被批量重建或无条件改写。
仍保留 native_pose_parity=false。Ogre 1.7 上游默认旋转模式是 RIM_LINEAR;不能把 glTF / Godot 插值直接说成与原版逐位相同。Ogre 1.7 Animation 源码。
正常场景接线
CoreSimBridge.ReactionAnimations 与 NativeReactionAnimationView:
- NPC 初始化尝试安装对应库,并保留明确的 readiness / reason。
- 校验骨骼名字、父子关系和静止姿态;使用已有原骨架合并的 1e-3 身份容差。
- 实测 Spear_Case 的旧导出 / 新导出旋转差约为 7e-7,逐矩阵元素相对比较会误拒绝;没有取消骨架检查,也不允许任意模型套用。
- 安装前停止播放器,保留原动作、位置、速度与队列后恢复。
- 对未知暂停速度的情况明确拒绝,不猜恢复倍率。
- 循环 / 非循环使用独立动作资源,不修改共享库。
- Play / Queue / Active 接收原索引;不消耗战斗 RNG,不写 AI 或技能状态。
- 节点退出清理视图引用。
骨骼 pose 是局部姿态,reset 会从 rest 写回局部 TRS;不是把任意骨架名字相同就认为兼容。Godot Skeleton3D 实现。本项目实际验证使用本地 Godot 4.7。
验证
- 2045 条核心断言通过。
- 440 项相关 Python 回归通过。
- Godot C# 构建零警告 / 零错误,190 个核心文件静态检查无硬错。
- 实际 Vulkan ECHO PASS 受测 NPC 正常初始化装入库。
- 原索引 12 / 13 都改变实际骨骼姿态。
- 活跃动作检查不引起重启,播放完成进入排队的原 IDLE。
- 动作传递前后模拟快照完全相同,不篡改 HP / RNG。
- 静止 IDLE、源文件哈希、导出动作集合、原索引和数据诊断均有回归。
GPU 探针显式提供已解析动作索引,隔离验证显示端;没有用它证明完整 NPC 反应决策已工作。
产物:
- build/f2/reaction_animations.json
- torchlight-2-poc/vanilla/reactions/
- build/reaction_animation_core.log
- build/reaction_animation_regression.log
- build/reaction_animation_visual/result.json
- build/reaction_animation_visual/reaction_12.webp
- build/reaction_animation_visual/reaction_13.webp
局部画面检查
已查看短边 512 的 HIT1 / HIT2 GPU 截图。两种动作姿态不同,身体 / 武器随骨架运动,未见分离或复制残影。UI 在探针中隐藏,没有据此评价正式 HUD。
| Receptor | 分数 / 2 |
|---|---|
| COMP-FOCAL-SINGLE | 2 |
| COMP-SIL-ACTION | 2 |
| MOT-VOL | 2 |
| MOT-GHOST | 2 |
| LIGHT-KEY-FILL | 1 |
9/10(90%,局部 A),零分项无;夜雨暗部仍影响观察。这是动作接线裁剪,不是原版逐帧姿态对拍或全游戏视觉认证。
继续清单
- 将 52CE50 的普通 NPC 分支接入真实 AI 标志、技能活动、取消和附着效果清理。
- 接入 ANIMATION_ALTS 与原活跃动画状态 / 排队语义。
- 消费反应动作的 KEY 音效 / 粒子事件。
- 核查并补齐 79 个未验证模型和其他地图所需导出库。
- 继续仇恨及 Charged Bolt,再逐武器开放并验收。
武器构造检查保持 1099 / 1419,273 阻塞、47 基础缺口、0 构造异常。全武器目标未完成。
按 godot-master 保持共享资源不被运行时改写、模拟决策与显示分离,并实际检查 GPU 画面。main 原地、未提交。默认存档 SHA256 未变: 9840fe858b6e311c73f8c2d4ed49912d59d71365f6278392811730e012d32a7f