技能活动、INTERRUPTABLE 与软结束请求:v47
2026-09-20。本批补 52CE50 所依赖的技能活动与软结束规则,并加入可保存的显式观测状态。普通 NPC 实时生产者及结束事件消费者仍未接完;不能宣称怪物已经完整可打断。
发现的关键差异
原反应分派调用 6D22D0(false,false,false),不是立即删除所有技能。
- +3C 是 CSkill 的 ACTIVATION_TYPE,不是怪物 AI 状态。
- 激活类型 4 跳过。
- 其他条目调用 6BE830,逐层检查 6C8690。
- 只有所有层都允许时,写 CSkill+F8 = 0.001f。
- 不删除技能、冷却、已有投射物或监听器,也不在这个函数里强制 AI 回到 idle。
因此将前端施法数组清空、直接设 fired=false 或销毁所有技能,并不是该调用的复刻。反应接口已改名为 RequestSkillSoftStop,防止消费者误读为立即取消。
51A5B0 技能是否仍在执行
输入是原字段,而不是前端 S_CAST / S_ATTACK 的猜测:
- 没有当前技能指针,返回 false。
- requested animation != -1,且 before-hit 为真,返回 true。
- 否则若 resolved animation != -1,且 5996F0 或 599560 查询为真,返回 true。
- 其余情况要求 elapsed < endTime 且未置 interrupted 字节。
这意味着:
- 没有活跃动画不一定代表技能结束;
- 活跃动画可以覆盖已到期的计时分支;
- timer fallback 的 NaN 比较仍按原 fcomp 路径返回 false;
- 运行时快照拒绝非有限计时输入。
NativeSkillActivitySnapshot 保存这些显式输入。生产者必须提供真实观测;不能把 AI 状态编号直接填成动画活动状态。
6C8690 层结束门
按原顺序:
- Remaining > 0:拒绝;
- 无 owner,或 definition animation != -1:允许;
- owner 活动查询或虚函数活动查询为非零:拒绝;
- 任一已登记 child 活跃:拒绝;
- 否则允许。
6BE830 在某一层拒绝后停止检查,不写结束计时。无层时允许写入 0.001f;这不是 min(oldTimer, .001),原值为负或更小时也会被覆盖。
原字段拼写与继承
真实字段为 INTERRUPTABLE:
- 6DC320 的 CSkillProperty+0xD1 初始化为 false;
- 有父属性对象时以父值作为缺省;
- 当前块显式写值才覆盖;
- 6C0C80 构造 LEVEL1 时继承根属性,后续 LEVEL 继承前一级;
- 6BE220 读取当前有效属性对象的 +0xD1;没有属性对象返回 false。
tools/build_skill_interrupt_flags.py 导出了 1659 个原技能的根与连续 LEVEL 标志,本次语料没有 BASEFILE 技能。若以后遇到 BASEFILE 子块合并,仍会明确标为 unverified,而不是凭平铺属性猜继承。
数据读入使用路径 / 等级,不按可能冲突的短名字静默挑选。
CoreSim 与 v47
新增 NativeActorSkillManagerSnapshot,包含:
- 当前活动观测;
- 原 +34 技能登记列表的稳定 ID、ActivationType、EndTimer;
- 各层结束条件及 child 活动数组。
SetActorSkillInterruptionState 校验并复制输入;RequestActorSkillSoftStop 生成新状态;捕获与恢复复制层级数组,避免外部修改快照影响实时状态。
实际伤害判定现在可以读取显式技能活动及 Interruptable 标志;调用上下文仍可明确提供已准备的值。未配置观测的旧数值通路保留既有兼容行为,不制造一个假的活动技能对象。
Godot 桥接提供显式观测入口,并从冻结目录绑定 INTERRUPTABLE;没有自动以现有 AI enum 填造原字段。
原代码与运行时验证
独立 32 位辅助进程执行:
- 51A5B0
- 6BE340
- 6C8690
- 6BE830
- 6D22D0(false,false,false)
模型活动、owner 活动和 child 活动是明确的输入边界。768 组返回结果及结束计时 bit pattern 全部匹配。
另外验证:
- 请求只改变允许条目的 EndTimer,不删除登记表;
- type 4、剩余时长和活动 child 保持正确阻止行为;
- v47 保存 / 恢复后软结束结果与 RNG 一致;
- 快照层数组不与实时状态别名;
- 实际 HIT 读取活动的可打断技能时产生 interrupt request;不可打断时不凭空产生;
- Godot 内的保存、请求及重放通过,操作不消耗 RNG。
结果:
- 2061 条核心断言通过。
- 443 项相关 Python 回归通过。
- Godot 检查 40 项通过。
- C# 构建零警告 / 零错误,192 个核心文件静态检查无硬错。
- 已有三元素桥接和四元素 GPU 回归通过。
产物:
- build/f2/skill_interrupt_flags.json
- build/native_skill_interrupt_oracle/results.json
- build/skill_interrupt_core.log
- build/skill_interrupt_regression.log
- build/skill_interrupt_build.log
- build/native_named_stat_engine/result.json
仍未完成
本批没有实现完整技能更新器。写入 0.001 并不等于其后 EVENT_END、粒子、伤害区域、状态与技能移除都已执行。后续需:
- 将正常 NPC 的真实技能 / 层活动观测接入该状态。
- 将 RequestSkillSoftStop 接进反应暂存宿主,避免在命中提交前改实时状态。
- 接上结束计时后的真实技能层 / EVENT_END 消费。
- 将动作恢复、仇恨与 Charged Bolt 等后续路径组合验证。
- 最后逐武器开放和验收,而不是撤销保护门。
构造覆盖仍为 1099 / 1419,273 阻塞、47 基础缺口、0 构造异常。全武器目标仍未完成。
遵循 godot-master 的权威状态 / 显示分离;本批不让前端清空数组冒充原技能生命周期。main 原地、未提交、未 attach 原游戏。默认存档 SHA256 未变: 9840fe858b6e311c73f8c2d4ed49912d59d71365f6278392811730e012d32a7f