These files were loaded only by their own test_*_parity.gd and never by the runtime (transitively checked, incl. client_phase_integration_system). Removes 76 manifest implementation/evidence references across 18 contracts; contract docs get a note that conclusions based on them are void. Live systems kept: chest, consumable, item_attr, metin_socket, whisper_chat. Full headless suite: no new failures (7 failing + 5 headless-hanging render tests are identical before the deletion). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
18 KiB
combat.attack_combo_damage
Scope
审计普攻、连击输入窗口、攻击动作状态包、.msa 命中窗口、碰撞命中、伤害包、击退/硬直、弓箭 FLY 帧和换图清理。
Reference call chain
CPythonPlayer::NEW_Attack- 检查 private shop、
__CanAttack、死亡/晕眩/施法/坐骑等级/弓箭条件。 - 按目标/方向调用
CInstanceBase::NEW_Attack或NEW_AttackToDestInstanceDirection。
- 检查 private shop、
CInstanceBase::InputComboAttack/__ComboProcess/__RunNextCombo- 根据职业、武器、坐骑、连击技能等级和
ComboInputData推进段号;动作结束时清理 combo。
- 根据职业、武器、坐骑、连击技能等级和
CPythonPlayerEventHandler::OnAttack- 每个动作段发送
FUNC_COMBO + motion index状态包。
- 每个动作段发送
CActorInstance::AttackProcess/__NormalAttackProcess- 在
.msa的 hit window 内用武器扫掠球和目标.msm防御球检测命中。
- 在
CPythonPlayerEventHandler::OnHit- 设置目标并发送
CG_ATTACK;根据受击方 owner、巨型/霸体和外力执行击退及同步位置。
- 设置目标并发送
CNormalBowAttack_FlyEventHandler_AutoClear- 起手
OnSetFlyTarget发送目标,.msa FLY帧OnShoot发送CG_SHOOT;事件处理器随旧 Actor/动作生命周期失效。
- 起手
Current call chain
NetPlay._on_pick/_update_auto_attack/_reserve_process_click_actor- 目标选择、攻击距离、自动攻击和预约追击。
NetPlay._do_attack_swing/_run_next_combo/_combo_process- 播放动作、发送
FUNC_COMBO、读取.msacombo/hit windows 和攻击速度。
- 播放动作、发送
NetPlay._attack_process/_normal_attack_process- 读取攻击者采样点、目标 defending spheres,执行 Z-cylinder 几何判定和 hit dedup。
NetPlay._process_attack_success/_on_hit- 受击动画、特效、硬直、击退、目标更新和
client.attack。
- 受击动画、特效、硬直、击退、目标更新和
GameScene._queue_shot/_on_local_motion_event(type=FLY)- 将弓箭技能先排队,等
.msa FLY帧再发送CG_SHOOT;_on_world_reset现在清理旧队列。
- 将弓箭技能先排队,等
Branch matrix
| 场景 | 40250 | 当前端 | 结论 |
|---|---|---|---|
| 普攻输入 | NEW_Attack 由方向/目标/按键分派,并受 CanAttack gates 限制 |
_on_pick、SPACE/auto attack 和 _do_attack_swing 已接入 |
PARTIAL:鼠标 press/release owner 不完全相同 |
| 连击段 | ComboInputData 的 start/next/end 时间和动作尾清理段号 |
.msa 数据、combo 表和 motion_bound 清理已实现 |
MAPPED + tests |
| 状态包 | 每段 FUNC_COMBO + motion index,技能使用 `FUNC_SKILL |
motion` | _send_state 发送对应 func/arg/位置 |
.msa 命中窗 |
AttackProcess 每帧扫掠真实武器球与 .msm 防御球 |
仅在有效 AttackingData/HitDataContainer 和真实 defending sphere/bone 存在时判定 |
FIXED + regression;WeaponTrace 视觉副作用仍未等价 |
| 命中限制 | m_HitDataMap、fInvisibleTime、hit limit、combo 每窗去重 |
_hit_dedup、invisible、limit 和 combo 分支已实现 |
MAPPED + tests |
| 受击后果 | OnHit 发 CG_ATTACK,按 owner/巨型/霸体决定击退和 sync position |
_process_attack_success / _on_hit 已映射 |
PARTIAL:服务端确认/死亡包实际闭环未 fixture 化 |
| 弓箭 | 起手 target,FLY 帧才 shoot;旧 handler 清除 | _pending_shots 等 FLY 帧发送;本轮已在 world reset 清空 |
MAPPED + regression |
| 换图/断线 | 旧 Actor handler 和动作状态失效,不带旧攻击事件 | reset 已清 shot queue,其他攻击/命中窗状态仍分散 | PARTIAL |
Equivalence matrix
| 项目 | 状态 | 证据 |
|---|---|---|
| Preconditions | MAPPED | _can_attack、safe/dead/stun/skill/mount/arrow gates 已定位 |
| Branch structure | PARTIAL | 鼠标 press/release、方向攻击、自动攻击、弓箭和坐骑完整排列不足 |
| Algorithms/formulas | PARTIAL | combo/hit geometry 已映射;缺失资源 fallback 已移除,WeaponTrace 和服务端伤害仍不等价 |
| State transition order | PARTIAL | 动作绑定、hit window、CG_ATTACK、击退和 sync position 顺序需包级证明 |
| Constants/units | PARTIAL | 攻击距离、speed ratio、hit limit、stiffen/invisible 等需从资源和 fixture 双证 |
| Timing/event sources | PARTIAL | 参考由 Actor motion event 驱动,当前由 Godot _process 和 signal 驱动 |
| Resource/data sources | PARTIAL | .msa/.msm 资源读取和缺失资源拒绝分支已接入;真实资源覆盖与 WeaponTrace 数据源仍未完全证明 |
| Protocol side effects | PARTIAL | FUNC_COMBO/CG_ATTACK/CG_SHOOT 已映射,真实服务端回包闭环未验证 |
| Interruption/failure/cleanup | PARTIAL | 本轮补了 pending shot;死亡、换图、断线、动作缺失和重复命中仍需测试 |
Regression evidence
project/combat_fx_test.gd:攻击锁定、连击段、hit window、命中去重、击退、抗击倒、弓箭 target/shoot 时序。project/combat_parity_test.gd:攻击锁、伤害数字和受击反馈。project/gamescene_test.gd:world reset 清理旧弓箭 FLY/CG_SHOOT 队列。extension/tests/net_state_queue_test.cpp:远端FUNC_ATTACK、FUNC_COMBO、FUNC_SKILL到达/动作状态。
Active GameLib weapon-trace review
GameLib/WeaponTrace.cpp/.h使用动态池,按武器骨骼矩阵采样时间点,构建连续刀光顶点带,并分别支持纹理/alpha、生命周期、采样间隔、reach scale、TurnOn/TurnOff 和清理;它是ActorInstance攻击动作的渲染副作用,不是一次性的命中特效。- 当前战斗链有
skill_fx、hit effect 和动作事件,但没有证明每个武器类型的骨骼采样、刀光顶点、alpha/texture 模式和跨动作清理与WeaponTrace相同;现有combat_fx_test只覆盖战斗桩和效果入口。 - 本轮完成
WeaponTrace活跃源码静态核对,攻击/连击合同继续为PARTIAL。
Status
PARTIAL。普攻/连击主体已经有较完整的本地模拟;当前已删除缺少有效动作攻击数据时的本地 CG_ATTACK 合成路径,但 WeaponTrace、服务端实际伤害结果和完整输入/生命周期矩阵仍未达到 40250 完全等价。
Audit round 2026-09-20T21:12Z
本轮沿 CActorInstance::AttackingProcess -> __NormalAttackProcess -> OnHit 重新核对当前攻击实现,并重跑 combat_fx_test、combat_parity_test、gamescene_test 和 23 项 native CTest:
- 状态包顺序、命中窗建立、
fInvisibleTime/hit-limit 去重、受击硬直/击退、弓箭 FLY 帧以及换图清理已有可执行实现和回归证据。 - 明确保留差异:当前
_emit_swing在缺少.msa命中窗时立即退化发送CG_ATTACK,_normal_attack_process在空 samples 时使用正前方/近距离兜底;40250 在没有有效m_pkCurRaceMotionData/HitDataContainer时不会合成这条本地命中路径。 WeaponTrace仍只有参考端源码证据,当前没有动态武器骨骼采样、刀光顶点带、alpha/texture 模式和动作中断回收的等价实现。- native CTest 首次串行回归出现一次
net.classic_encstream的加密头断言失败,单测复跑和全量复跑均通过;暂记为测试环境/时序抖动,不作为本轮攻击实现通过依据。
结论:缺失资源 fallback 已按 40250 的无有效攻击数据分支修复;WeaponTrace 和真实服务端伤害/死亡/击退包序进入下一轮修复候选,合同保持 PARTIAL。
Audit and implementation round 2026-09-21
沿 ActorInstanceBattle.cpp::ComboAttack、ActorInstanceMotion.cpp::__SetMotion 和
PythonPlayerEventHandler::OnAttack 重新核对事件顺序,确认参考端是:先绑定
InterceptOnceMotion(同时绑定攻击数据、清理命中表,并触发弓箭 OnSetFlyTarget),再由
__OnAttack 发送 FUNC_COMBO + motion index。当前端原先在 _emit_swing 中先发状态包、再绑定
Godot 动作,存在服务端状态已发出但本地命中窗口尚未建立的顺序差异。
本轮已调整为“绑定动作/建立命中窗口 → 弓箭 SetFlyTarget → 发送 FUNC_COMBO”,并新增
combat_fx_test.gd 的跨对象顺序断言;combat_fx_test.gd、combat_parity_test.gd、
gamescene_test.gd 均通过。
仍保持 PARTIAL:当前没有 WeaponTrace 的骨骼采样/刀光生命周期实现,也没有真实服务器对
CG_ATTACK、CG_SYNC_POSITION、死亡/伤害/击退包的端到端 fixture;弓箭和攻击状态在换图、
断线、动作中断后的全部清理仍需要继续核对。
Implementation fix round 2026-09-20T21:18Z
按 40250 CActorInstance::isValidAttacking 与
ActorInstanceCollisionDetection.cpp::__NormalAttackProcess 修复攻击命中源:
NetPlay::_emit_swing不再在缺少当前动作AttackingData/HitDataContainer时直接发送CG_ATTACK;仍只发送动作对应的FUNC_COMBO状态包,真正的CG_ATTACK只能由命中处理链触发。NetPlay::_attack_process现在要求当前动作存在有效AttackingData和命中窗;空命中窗不命中。_defending_spheres不再为缺少.msm防御球的节点合成占位胶囊;空m_DefendingPointInstanceList直接无命中。combat_fx_test.gd、netplay_test.gd增加缺少动作攻击数据和缺少防御球的反例,combat_parity_test.gd、playable_combat_test.gd同步回归通过。
本轮修复了“缺失资源仍产生本地命中”的结构差异;WeaponTrace 骨骼采样/刀光生命周期、
真实服务端伤害确认和死亡/击退包序仍保持 PARTIAL。
Audit round 2026-09-20T21:24Z — WeaponTrace call-chain review
本轮只做差异审计,没有把现有 has_trail 配置字段或一次性 .mse 特效误判为
WeaponTrace 已实现。沿 40250 的完整调用链核对结果如下:
ActorInstanceAttach.cpp::AttachWeapon仅对非 bell/fan/bow 武器创建CWeaponTrace,并绑定武器模型实例;当前equip_model.gd只设置weapon_gr2/shield_gr2与强化.mse,没有按武器类型创建轨迹对象。ActorInstance::INSTANCEBASE_Deform每帧执行TraceProcess;当前PlayerView/Metin2Model没有对应的每帧武器骨骼采样出口。CWeaponTrace::Update同时维护 short/long 两条世界坐标时间队列,使用默认lifeTime=0.18s、samplingTime=0.003s、武器 bound-box 长度和__GetReachScale()生成刀根/刀尖采样;当前端没有时间队列、reach scale、采样间隔 或真实武器骨骼矩阵等价物。CWeaponTrace::BuildVertex/Render用 cubic spline 生成 triangle strip,分别提供 alpha/texture 渲染模式;当前端没有 WeaponTrace mesh、顶点带、材质模式或独立RenderTrace阶段。socket_glow_fx_system.gd的has_trail只是强化配置结果, 没有消费方。ActorInstanceMotion.cpp::__SetMotion在绑定新动作前统一__HideWeaponTrace, 成功绑定可攻击动作后__ShowWeaponTrace;Destroy/Clear删除全部 trace,TurnOff保留旧队列以便自然淡出。当前_bind、播放结束、换装、换图和销毁路径 都没有这一组开关/淡出/清理语义。
现有证据:player_motion_test.gd、combat_fx_test.gd、combat_parity_test.gd 和
playable_combat_test.gd 通过,但它们只能证明动作/战斗门和命中链,不能证明刀光。
weapon_attach_test.gd 当前还存在 race 0 的 03150 双手动作左手贴合断言失败并伴随
exit 139;该失败属于武器动作绑定的独立问题,也说明不能用当前武器挂点测试替代
WeaponTrace 证据。
结论:combat.attack_combo_damage 继续为 PARTIAL。下一次实现应新增独立
WeaponTrace 适配层,并在真实武器模型上验证“创建过滤 → 动作开关 → 双轨迹采样 →
刀光网格/alpha → 动作中断自然淡出 → 换装/换图销毁”的全链路;在此之前不得声称
40250 的武器刀光已经复刻。
Implementation round 2026-09-20 — WeaponTrace adapter
已新增 project/ui/weapon_trace.gd,并将它接入
project/ui/player_view.gd 与 project/ui/equip_model.gd,对应 40250 的以下调用边界:
EquipModel._weapon_trace_enabled()对 bell/fan/bow 不创建刀光,普通武器才允许创建;换装和空武器路径执行 detach/clear/free。PlayerView._refresh_weapon_trace()在附着的Weapon模型上建立 trace;_bind()在绑定新动作前TurnOff,攻击/连击动作成功绑定后TurnOn,播放结束保留旧点并自然淡出。WeaponTrace._process()每帧维护 short/long 世界坐标时间队列;默认0.18s生命周期、0.003sspline 采样步长,并复刻参考端三对角 cubic spline 与 triangle strip 顶点交错。StandardMaterial3D提供双面、透明、无光照、不写深度的 alpha 路径,并保留 texture/alpha 两种模式;独立weapon_trace_test.gd覆盖附着、采样、网格、TurnOff 尾迹、过期、重挂和 PlayerView 攻击开关。
当前仍有明确适配差异,不能标记为完全一致:Godot 端点由 attached weapon 的 mesh AABB 推导,尚未由 native bone matrix 直接提供
m_fLength * __GetReachScale() 的同一坐标语义;远端/怪物渲染覆盖、lot_ade10-2.tga
真实视觉资源和服务端动作资源驱动的截图证据仍缺;weapon_attach_test.gd 的 race 0 /
03150 双手动作左手贴合断言仍失败并 exit 139。socket_glow_fx_system.gd::has_trail
仍是独立强化配置,不能当作 WeaponTrace 消费方。
结论:本轮把 WeaponTrace 从“生产链缺失”修复为“生产链已接入、核心生命周期有证据、坐标端点和覆盖范围仍 PARTIAL”。
Implementation fix round 2026-09-21T03:42Z — MainInstance damage billboard
沿 40250 PythonNetworkStreamPhaseGame::RecvDamageInfoPacket →
CInstanceBase::AddDamageEffect → CInstanceBase::ProcessDamage 复核本地伤害显示:
参考端只要 CharacterManager 找到目标实例,且目标就是 MainInstance,仍会按
bSelf 入伤害队列并在本地主角上显示 damage_*.dds/MISS。
当前端 GameScene 为避免把本地主角重复挂入 _by_vid,将其单独保存为 _local_node。
修复前 NetWorld._process_damage_queue() 只从 _by_vid 取节点,导致本地主角自己的
伤害包已经入队,却在渲染前被静默丢弃。现在对本地 VID 使用 _local_node 回退,保持
普通远端 actor 与 MainInstance 的同一 ProcessDamage 分类和渲染路径。
新增 project/damage_local_main_parity_test.gd,修复前专项回归失败,修复后通过;
合同仍为 PARTIAL,因为服务端真实伤害/死亡包、WeaponTrace 坐标端点、远端/怪物覆盖和
攻击生命周期清理尚未达到 40250 完全等价。
Implementation fix round 2026-09-21T03:46Z — multi-part WeaponTrace
沿 ActorInstanceAttach.cpp::__IsRightHandWeapon、__IsLeftHandWeapon 和
CActorInstance::AttachWeapon 继续核对:参考端不是每个角色只有一个刀光。
匕首会同时挂 PART_WEAPON 与 PART_WEAPON_LEFT,骑马扇也可能有双部件;每个可追踪
部件都独立创建一个 CWeaponTrace,并由 m_WeaponTraceVector 统一执行开关、纹理和
清理操作。
修复前当前 PlayerView._refresh_weapon_trace() 只查找 Weapon 并维护一个对象,
因此第二个部件的刀光不会出现。现在按 Weapon、Shield 部件顺序维护多条 trace,
逐部件执行 attach/TurnOn/TurnOff/detach,并补齐对应的纹理、Texture/Alpha 模式
控制入口。新增 project/weapon_trace_multi_part_parity_test.gd,修复前回归失败,
修复后与 weapon_trace_test.gd、equip_model_test.gd、weapon_attach_test.gd、
player_motion_test.gd 和 combat_fx_test.gd 一起通过。
仍为 PARTIAL:当前刀根/刀尖端点仍由 Godot mesh AABB 推导,不是参考端骨骼矩阵加
__GetReachScale();远端/怪物 trace 覆盖、真实刀光纹理视觉和服务端攻击闭环仍未证明。
Implementation fix round 2026-09-21T03:55Z — WeaponTrace geometry and reach scale
本轮继续沿 40250 的 GameLib/WeaponTrace.cpp、
InstanceBaseEffect.cpp::__Warrior_SetGeomgyeongAffect 和
ActorInstanceCollisionDetection.cpp::__NormalAttackProcess 核对端点与攻击扫掠:
- 参考端在
SetWeaponInstance中从武器 bound box 到骨骼原点计算m_fLength,Update再沿武器局部 Z 轴使用m_fLength * fReachScale生成刀尖; 当前端不再把任意 AABB 角点当作方向,而是取 attached mesh AABB 的最大半径作为长度, 沿局部 Z 轴延伸,并提供可验证的reach_scale。 - 参考端
AFFECT_GEOMGYEONG开启时把 reach scale 设为1.5,关闭时恢复1.0; 当前PlayerView将该状态广播到所有 Weapon/Shield trace,并在重新附着时保留当前值。 - 参考端普通攻击把
dsiSrc.v3Position - dsiSrc.v3LastPosition乘以__GetReachScale()后再参与碰撞变换;当前NetPlay._normal_attack_process通过_attack_sample_positions对同一段位移应用该缩放,因此视觉刀光和命中扫掠共用同一 reach scale 来源。
修复前专项回归分别复现了端点方向/长度错误及缺少 reach scale API、Geomgyeong 未改变
reach scale、攻击采样没有暴露 reach-scaled endpoint;修复后以下测试通过:
weapon_trace_endpoint_parity_test.gd、weapon_trace_reach_affect_parity_test.gd、
weapon_reach_scale_attack_parity_test.gd、weapon_trace_multi_part_parity_test.gd、
weapon_trace_test.gd、combat_fx_test.gd、combat_parity_test.gd、
playable_combat_test.gd、test_combat_status_effect_parity.gd、netplay_test.gd。
合同仍为 PARTIAL:当前端点的长度输入来自 Godot attached mesh AABB,尚未直接消费
native CActorInstance 的同一骨骼 composite matrix、旋转和绑定坐标语义;远端/怪物
覆盖、真实刀光纹理视觉、服务端真实攻击/死亡包级 fixture 和跨动作/断线清理仍未闭合。
Audit evidence reconciliation 2026-09-21T04:00Z
重新运行当前工作树的 weapon_attach_test.gd,加载 00010.gr2 和 03150.gr2 均正常,
进程退出码为 0;此前记录的 race 0 / 03150 左手贴合断言失败不再是当前待办项,已从
manifest 的 remaining 移除。该校正只更新证据状态,不改变 WeaponTrace native
骨骼 composite matrix、远端/怪物覆盖和服务端攻击闭环仍未证明的结论。
2026-09-22 死代码删除
以下文件只被自身测试引用、运行时从不加载,已删除;本文中以它们为实现或证据的结论作废,相关行为需按 40250 源码单元重新移植:socket_glow_fx_system.gd, test_combat_status_effect_parity.gd。