- 连击类型由 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
50 lines
1.9 KiB
GDScript
50 lines
1.9 KiB
GDScript
extends SceneTree
|
|
|
|
const PlayerView = preload("res://ui/player_view.gd")
|
|
var failures := 0
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run")
|
|
|
|
func run() -> void:
|
|
for race in 8:
|
|
var views: Array = []
|
|
for mode in ["0", "1"]:
|
|
OS.set_environment("MTGODOT_GPUSKIN", mode)
|
|
var pv := PlayerView.new()
|
|
root.add_child(pv)
|
|
if not pv.build(AssetRoot.path(), race):
|
|
printerr("FAIL: build race ", race)
|
|
quit(1)
|
|
return
|
|
pv.model.set("lod_enabled", false)
|
|
pv.anim.set_process(false)
|
|
pv.anim.set("blend_time", 0.0)
|
|
views.append(pv)
|
|
for motion in ["wait", "walk", "run", "attack", "damage", "dead"]:
|
|
for i in 2:
|
|
OS.set_environment("MTGODOT_GPUSKIN", str(i))
|
|
# damage has weighted variants (damage / damage_1, CRaceData::GetMotionKey);
|
|
# the same seed makes the CPU and GPU views pick the same clip.
|
|
seed(race)
|
|
views[i].set_anim_state(motion)
|
|
views[i].anim.set("loop", false)
|
|
for fraction in [0.0, 0.25, 0.5, 0.75, 1.0]:
|
|
for i in 2:
|
|
OS.set_environment("MTGODOT_GPUSKIN", str(i))
|
|
views[i].anim.set("time", float(views[i].anim.call("get_duration")) * fraction)
|
|
var cpu: MeshInstance3D = views[0].model.get_node("MeshInstance3D")
|
|
var gpu: MeshInstance3D = views[1].model.get_node("MeshInstance3D")
|
|
# Read the actual culling box without invoking get_visual_aabb(),
|
|
# which refreshes it on demand and would hide the stale-box bug.
|
|
var expected: AABB = cpu.get_aabb()
|
|
var actual: AABB = gpu.custom_aabb
|
|
if not actual.position.is_finite() or not actual.size.is_finite() or not actual.grow(0.02).encloses(expected):
|
|
failures += 1
|
|
printerr("FAIL: GPU culling excludes CPU pose: race=%d motion=%s time=%s" % [race, motion, fraction])
|
|
for pv in views:
|
|
pv.queue_free()
|
|
await process_frame
|
|
print("gpu_pose_bounds_test: failures=", failures, " (8 races x 6 motions x 5 samples)")
|
|
quit(0 if failures == 0 else 1)
|