原版受击反应分派:52CE50
2026-09-20。本批补齐受击反应控制流、原代码对照及 HIT 事务连接,不是宣布普通 NPC 受击动画 / AI / 技能中断已完整接入。快照继续使用 v46。
与已有 HitReaction 的区别
原有 HitReaction.cs 对应 548850 中的打断概率、impact force 和偏航随机数。52CE50 是另一层:读取 AI / 模型 / 技能 / 状态,按序取消技能、选择动作、切换状态及清理附着效果。
新增 NativeHitReaction.Run 使用必须由暂存宿主实现的接口;不能绑定到实时 Godot 节点后边执行边失败。动画选择、技能取消及相关回调会影响后续输入,因此保留原读取顺序。
分支规则
- AI 标志 2(CANNOT INTERRUPT)拒绝;无模型拒绝。
- native state 为 16 / 41 / 40 / 35 / 12 / 50 / 51 时入口拒绝;另检查单位 +7E0 字节。
- 若 51A5B0 判断当前技能仍在执行,检查 +370 的可打断标志。仅“有技能指针”不等于仍在执行。
- 可打断技能缺少 HIT 前缀动作且不是 PLAYER 时,先解析 IDLE、播放其索引并切到 state 0,随后继续通知 / 清理流程。
- playRequested=true 时,没有 HIT 前缀或为 PLAYER 会返回 false。
- 通知之后再次检查 native state / alive;不能缓存入口值。
- 清零 +348 / +358 计时及 +27B before-hit,再取消技能。
- 取消之后再次检查动作是否存在,选择动作并先保存 +374。
- 若选中的动作已经活跃,不重启、不再次强制 state 29;但前面的取消与后面的清理仍发生。
- 否则播放选中动作、排队 IDLE,再设置 state 29。
- playRequested=false 且当时 state 48 时回到 0。
- 最后调用 stagger(false,true),按原顺序停止两组附着效果,并标记另外两组退场。
两个特别容易丢失的语义:
- false 返回值不保证没发生过改变。 IDLE 回退可能已经播放并改变状态,之后通知导致 state 16,函数才返回 false。因此不能以返回 false 为由丢弃所有已准备动作。
- 玩家不套怪物 HIT 动画。 对四元素调用使用的 playRequested=true,PLAYER 路径不取消技能或播放 HIT;这不代表其他使用 playRequested=false 的打断调用也无效。
反编译参数纠正
527710 的真实栈参数是动作索引、循环标志、blend、speed、duration 及最后一个布尔值。52CF47 先调用 IDLE 解析器,52CF4C 把返回索引入栈。
Hex-Rays 伪代码里看起来多出来的名字参数不是实际栈参数。不能把“HIT 名称 + IDLE 索引”作为生产播放接口。
独立原代码检查验证固定参数的原始 float bits:
- blend = 0x3E4CCCCD(0.2f)
- speed = 0x3F800000(1.0f)
- duration = 0xBF800000(-1.0f)
辅助 C 检查按位校验,避免宿主 x87 的额外精度把浮点常量比较误报成参数错误。
原版机器码对照
tools/build_native_hit_reaction_oracle.py 在独立 32 位辅助进程中映射原 EXE 字节:
- 执行原 52CE50 和入口状态辅助函数 518790;
- 覆盖 644 组门条件、状态、玩家、施法、重复动作、网络条件以及重入变化;
- 对照返回值、最终状态、计时清零、保存的动作索引、附着效果退场标志,以及回调顺序;
- 模型 / AI / 技能查询、动作选择和播放、网络包、stagger 及附着效果 API 使用明确的宿主边界;
- 没有声称这些被替代的子系统也已原代码等价。
部分随机组合最初不满足原网络路径的前提:网络关联角色必须有 level,取消包路径会直接解引用它。输入生成器现在排除这种无效组合,没有修改原函数绕过访问。
未 attach 正在运行的原版游戏。原 EXE SHA256: 186472c3057b38f4cdff4696959a943c396ae6166995f7418997b5ea853e8a5e
HIT 事务与已接通分支
NativeElementalTransfers 在没有外部反应适配器时,仅自动处理能证明不改变本地模拟的两类情况:
- 原 UnitTypeTable 确认为 PLAYER(不是仅看移植端 IsPlayer 记账标志);
- 原入口直接拒绝的明确 native state。
这是现有单人模拟的本地语义。6E18B0 的原通知路径面向网络连接发送,不把网络包机制冒充为已实现的多人行为。
验证了实际 HIT:
- 状态 16 保持原状态,但元素转移继续;
- PLAYER 得到元素触发器,不制造受击动画 / 状态切换;
- 角色记账角色是玩家、实际类型却不是 PLAYER 时,不会错误短路;
- 保存 / 恢复后状态与 RNG 一致。
另外使用明确模型 / 技能输入夹具将真实控制器放入实际 HIT 事务:
- 同一命中的两个元素共享同一个暂存反应状态;
- 第一次播放 HIT,第二次仍选择动作 / 取消,但不重启同一个活跃动作;
- 后续效果转移失败时,前面准备的状态变化和 RNG 全部回滚。
普通 NPC 仍报 elemental_reaction_runtime_unbound,直到真实场景适配器完成。不能把该保护门换成空委托。
仍待生产绑定
- AI CANNOT INTERRUPT、单位 +7E0、51A5B0 技能活动条件与实时状态。
- 原模型的 HIT 前缀动作库 / 原索引及 WeightedRandom 选择;不能只查当前导出的 idle/run/attack/die 子集。
- 技能取消后的附着效果、统计变化和 post-reaction 来源属性投影。
- HIT / IDLE 的播放、排队及活跃动作判断。
- 角色仇恨广播 / 目标设置与 Charged Bolt 的技能安装、触发、移除。
本次还读取了 5DEEB0 / 522190 / 51A830 等仇恨相关函数,用于下一段接线;没有把只读取源代码算作仇恨已经修复。
验证与产物
- 644 组原机器码对照完全匹配。
- 2037 条核心断言通过。
- 434 项相关 Python 回归通过。
- Godot C# 构建零警告 / 零错误,188 个核心 C# 静态检查无硬错。
- 独立 Godot 检查新增受保护状态分支,共 37 项通过。
- 三元素正式桥接与四元素 GPU 场景回归通过。
日志 / 结果:
- build/native_hit_reaction_oracle/results.json
- build/native_hit_reaction_core.log
- build/native_hit_reaction_regression.log
- build/native_hit_reaction_build.log
- build/native_named_stat_engine/result.json
武器构造覆盖仍为 1099 / 1419;273 阻塞、47 基础缺口、0 构造异常,未扩大准入。全武器目标尚未完成。
按 godot-master 保持权威状态与表现分离。main 原地、未提交,默认存档 SHA256 未变: 9840fe858b6e311c73f8c2d4ed49912d59d71365f6278392811730e012d32a7f