feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复

- 桥梁与静态物体高度采样修复:
  - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight
  - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程
  - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题
  - 新增 test_bridge_height_parity.gd 自动化对拍测试
- 40250 怪物击杀经验动效:
  - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附
- 40250 客户端全系统功能对齐(Batches 1-31):
  - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试
- 文档沉淀:
  - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
This commit is contained in:
shen
2026-09-19 08:51:25 -07:00
parent 1db9e9a129
commit 66d217b313
650 changed files with 53046 additions and 1586 deletions
+87
View File
@@ -0,0 +1,87 @@
# test_refine_effect_parity.gd —— 验证方向 3+7/+8/+9 装备专属发光特效 40250 1:1 对齐
extends SceneTree
const RefineEffectSystem = preload("res://refine_effect_system.gd")
var _passed := 0
var _failed := 0
func _assert(cond: bool, msg: String) -> void:
if cond:
_passed += 1
print(" [PASS] %s" % msg)
else:
_failed += 1
printerr(" [FAIL] %s" % msg)
func _init() -> void:
print("\n=== Running test_refine_effect_parity (Direction 3: Refine Shine Effects 1:1) ===")
test_refine_level_extraction()
test_shine_threshold_check()
test_weapon_shine_specs()
test_armor_shine_specs()
test_particles_generation()
print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed])
if _failed > 0:
printerr("TEST FAILED!")
quit(1)
else:
print("ALL TESTS PASSED!")
quit(0)
func test_refine_level_extraction() -> void:
print("\n--- Test 1: Vnum to Refine Level Extraction ---")
_assert(RefineEffectSystem.get_refine_level_from_vnum(10) == 0, "Sword+0 (vnum 10) is level 0")
_assert(RefineEffectSystem.get_refine_level_from_vnum(16) == 6, "Sword+6 (vnum 16) is level 6")
_assert(RefineEffectSystem.get_refine_level_from_vnum(17) == 7, "Sword+7 (vnum 17) is level 7")
_assert(RefineEffectSystem.get_refine_level_from_vnum(18) == 8, "Sword+8 (vnum 18) is level 8")
_assert(RefineEffectSystem.get_refine_level_from_vnum(19) == 9, "Sword+9 (vnum 19) is level 9")
func test_shine_threshold_check() -> void:
print("\n--- Test 2: Shine Activation Threshold (Level >= 7) ---")
_assert(not RefineEffectSystem.is_shining_item(10, 1), "Sword+0 does not shine")
_assert(not RefineEffectSystem.is_shining_item(16, 1), "Sword+6 does not shine")
_assert(RefineEffectSystem.is_shining_item(17, 1), "Sword+7 activates shine")
_assert(RefineEffectSystem.is_shining_item(18, 1), "Sword+8 activates shine")
_assert(RefineEffectSystem.is_shining_item(19, 1), "Sword+9 activates shine")
_assert(not RefineEffectSystem.is_shining_item(27001, 3), "Potions do not shine")
func test_weapon_shine_specs() -> void:
print("\n--- Test 3: 40250 Weapon Shine Specs (InstanceBase.cpp:2698) ---")
var spec7 := RefineEffectSystem.get_shine_spec(17, 1, false)
_assert(spec7.shining and spec7.level == 7, "Sword+7 spec has level 7")
_assert(spec7.attach_bone == RefineEffectSystem.ATTACH_BONE_WEAPON_RIGHT, "Sword attached to PART_WEAPON")
_assert("sword_7.mse" in spec7.effect_path, "Sword+7 uses sword_7.mse")
var spec8 := RefineEffectSystem.get_shine_spec(18, 1, false)
_assert("sword_8.mse" in spec8.effect_path, "Sword+8 uses sword_8.mse")
var spec9 := RefineEffectSystem.get_shine_spec(19, 1, false)
_assert("sword_9.mse" in spec9.effect_path, "Sword+9 uses sword_9.mse")
_assert(spec9.light_energy > spec7.light_energy, "+9 has higher light energy than +7")
# Dual daggers left hand attachment
var spec_left := RefineEffectSystem.get_shine_spec(1179, 1, true)
_assert(spec_left.attach_bone == RefineEffectSystem.ATTACH_BONE_WEAPON_LEFT, "Left hand weapon attached to PART_WEAPON_LEFT")
func test_armor_shine_specs() -> void:
print("\n--- Test 4: 40250 Armor Shine Specs (InstanceBase.cpp:2739) ---")
# Regular armor +9 (11209)
var spec_armor9 := RefineEffectSystem.get_shine_spec(11209, 2)
_assert(spec_armor9.shining and spec_armor9.level == 9, "Armor+9 has shine")
_assert(spec_armor9.attach_bone == RefineEffectSystem.ATTACH_BONE_ARMOR, "Armor attached to Bip01")
_assert("armor_9.mse" in spec_armor9.effect_path, "Armor+9 uses armor_9.mse")
# Special Lv 66+ Black Steel Armor +9 (11299) -> special dragon aura
var spec_special := RefineEffectSystem.get_shine_spec(11299, 2)
_assert("armor-4-2.mse" in spec_special.effect_path, "Lv 66+ armor uses special armor-4-2.mse effect")
func test_particles_generation() -> void:
print("\n--- Test 5: Godot Particle Node Generation ---")
var spec := RefineEffectSystem.get_shine_spec(19, 1)
var p: GPUParticles3D = RefineEffectSystem.create_shine_particles(spec)
_assert(p != null, "GPUParticles3D created successfully")
_assert(p.name == "RefineShineParticles_L9", "Particle node named properly")
_assert(p.draw_pass_1 is QuadMesh, "Draw pass mesh is configured")
p.free()