fix(combat): 战斗逐项对齐 40250,修复移动 / 技能释放与武器挂点
- 连击类型由 combo_changed 驱动(SetComboSkillFlag,技能 122 等级) - 命中判定改为 .msa 刀尖 Z 圆柱 vs .msm 防御球(hit_collision.gd 逐行移植) - _register_hit 改为 map::insert 语义,修正命中上限 - 攻速同时缩放 GetAttackingElapsedTime 与攻击动作速率;按武器动作模式目录绑定攻击段 - 去掉本地连击超时,motion_bound 清命中表 / 连击段号 - __ProcessDataAttackSuccess:InsertDelay 硬直、physics_push.gd 击退 + GetBlendingPosition 同步、 命中特效、__HitGood / __HitGreate / __HitStone 受击动作链与抖动(ui/hit_reaction.gd) - ClassicSession::send_use_skill 不再夹带 CG_FLY_TARGETING - mac 前进 / 后退方向与技能释放修复;武器按职业骨骼挂到手上 - 新增 hit_collision / physics_push / hit_view / net_world_push / weapon_attach 测试; gpu_pose_bounds / race_motion_assembly 适配 damage 随机变体 - 文档:CLIENT-GAP.md、CLIENT-GAP-FIX.md §3.5 / §3.7 与 C.5 增量 130 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ft3kXpNdLbKEfg5uDLfqVF
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# hit_collision_test —— §3.5:__NormalAttackProcess 的碰撞几何 headless 自检。
|
||||
# IntersectLineSegments(EterLib/lineintersect_utils.cpp)
|
||||
# DetectCollisionDynamicZCylinderVSDynamicZCylinder(GameLib/GameUtil.cpp)
|
||||
# .msm AttachingData CollisionType 3 = m_DefendingPointInstanceList
|
||||
# godot --headless --path project --script hit_collision_test.gd
|
||||
extends SceneTree
|
||||
|
||||
const HitCollision = preload("res://hit_collision.gd")
|
||||
|
||||
var _fail := 0
|
||||
func _ck(c: bool, m: String) -> void:
|
||||
if not c:
|
||||
_fail += 1
|
||||
printerr("FAIL: " + m)
|
||||
|
||||
func _init() -> void:
|
||||
_run()
|
||||
if _fail == 0:
|
||||
print("PASS: hit_collision_test (segments / z-cylinder / msm defending)")
|
||||
quit(0)
|
||||
else:
|
||||
printerr("%d check(s) failed" % _fail)
|
||||
quit(1)
|
||||
|
||||
func _near(a: Vector3, b: Vector3) -> bool:
|
||||
return a.distance_to(b) < 0.01
|
||||
|
||||
func _run() -> void:
|
||||
# --- IntersectLineSegments ---
|
||||
# 静止受击方(L22 < ε²):OutB = B1,OutA = A 上离 B1 最近点。
|
||||
var r: Array = HitCollision.intersect_line_segments(
|
||||
Vector3(-100, 0, 0), Vector3(100, 0, 0), Vector3(0, 50, 0), Vector3(0, 50, 0))
|
||||
_ck(_near(r[0], Vector3.ZERO) and _near(r[1], Vector3(0, 50, 0)), "stationary B -> nearest on A = (0,0,0)")
|
||||
# 退化 A(L11 < ε²)
|
||||
r = HitCollision.intersect_line_segments(
|
||||
Vector3(10, 10, 0), Vector3(10, 10, 0), Vector3(0, 0, 0), Vector3(100, 0, 0))
|
||||
_ck(_near(r[0], Vector3(10, 10, 0)) and _near(r[1], Vector3(10, 0, 0)), "degenerate A -> OutB (10,0,0)")
|
||||
# 平行(|DetL| < ε):两段 clamp 参数取中点
|
||||
r = HitCollision.intersect_line_segments(
|
||||
Vector3(0, 0, 0), Vector3(100, 0, 0), Vector3(0, 50, 0), Vector3(100, 50, 0))
|
||||
_ck(_near(r[0], Vector3(50, 0, 0)) and _near(r[1], Vector3(50, 50, 0)), "parallel -> midpoints (50,0)/(50,50)")
|
||||
# 一般情形,s/t 双越界 -> AdjustNearestPoints
|
||||
r = HitCollision.intersect_line_segments(
|
||||
Vector3(0, 0, 0), Vector3(100, 0, 0), Vector3(200, -50, 0), Vector3(200, 50, 0))
|
||||
_ck(_near(r[0], Vector3(100, 0, 0)) and _near(r[1], Vector3(200, 0, 0)), "both out of range -> (100,0)/(200,0)")
|
||||
# 参考端 rb = +dot(Lb, AB)(注释里是负号):两条运动段十字相交时 t 被算成 -0.5,
|
||||
# 经 AdjustNearestPoints 夹到 B1。1:1 保留这个出货行为。
|
||||
r = HitCollision.intersect_line_segments(
|
||||
Vector3(-100, 0, 0), Vector3(100, 0, 0), Vector3(0, -100, 0), Vector3(0, 100, 0))
|
||||
_ck(_near(r[0], Vector3.ZERO) and _near(r[1], Vector3(0, -100, 0)),
|
||||
"shipped rb sign: crossing moving segments -> OutB clamps to B1, got %s / %s" % [r[0], r[1]])
|
||||
|
||||
# --- DetectCollisionDynamicZCylinderVSDynamicZCylinder ---
|
||||
# 攻击球扫过静止受击球:只看扫掠段,不看端点;z(高度)清零。
|
||||
_ck(HitCollision.detect_z_cylinder(Vector3(-200, 0, 500), Vector3(200, 0, 500), 20.0,
|
||||
Vector3(0, 60, 0), Vector3(0, 60, 0), 70.0), "sweep passes 60cm from victim, r 20+70 -> hit (height ignored)")
|
||||
_ck(not HitCollision.detect_z_cylinder(Vector3(-200, 0, 0), Vector3(200, 0, 0), 20.0,
|
||||
Vector3(0, 100, 0), Vector3(0, 100, 0), 70.0), "sweep passes 100cm away -> no hit")
|
||||
_ck(not HitCollision.detect_z_cylinder(Vector3(-200, 0, 0), Vector3(200, 0, 0), 20.0,
|
||||
Vector3(400, 0, 0), Vector3(400, 0, 0), 70.0), "AABB reject -> no hit")
|
||||
_ck(HitCollision.detect_z_cylinder(Vector3(0, 0, 0), Vector3(0, 0, 0), 20.0,
|
||||
Vector3(80, 0, 900), Vector3(80, 0, 900), 70.0), "static spheres 80cm apart, r sum 90 -> hit")
|
||||
|
||||
# --- .msm 防御球(CollisionType 3),CollisionType 1 = body 不算 ---
|
||||
var assets := AssetRoot.path()
|
||||
var wolf := assets.path_join("Monster/ymir work/monster/wolf/wolf_blue.msm")
|
||||
var ds: Array = HitCollision.parse_msm_defending(wolf)
|
||||
_ck(ds.size() == 1, "wolf_blue.msm -> 1 defending sphere, got %d" % ds.size())
|
||||
if ds.size() == 1:
|
||||
_ck(is_equal_approx(float(ds[0].radius), 90.0) and _near(ds[0].pos, Vector3(0, -15, 80)),
|
||||
"wolf defending sphere r90 (0,-15,80), got %s" % [ds[0]])
|
||||
var war := assets.path_join("root/msm/warrior_m.msm")
|
||||
ds = HitCollision.parse_msm_defending(war)
|
||||
_ck(ds.size() >= 1 and is_equal_approx(float(ds[0].radius), 70.0) and _near(ds[0].pos, Vector3(0, 0, 100)),
|
||||
"warrior_m.msm defending sphere r70 (0,0,100), got %s" % [ds])
|
||||
_ck(HitCollision.parse_msm_defending(assets.path_join("no/such.msm")).is_empty(), "missing msm -> []")
|
||||
# IS_HUGE_RACE(InstanceBase.cpp)
|
||||
_ck(HitCollision.is_huge_race(2493) and not HitCollision.is_huge_race(101), "IS_HUGE_RACE: only 2493")
|
||||
Reference in New Issue
Block a user