Files
mtgodot-poc/project/test_combat_replay_snapshot_parity.gd
T
shenandshen 66d217b313 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 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

141 lines
5.3 KiB
GDScript

# test_combat_replay_snapshot_parity.gd —— 40250 战斗高光战报与首领击杀快照 1:1 回归测试套件
extends SceneTree
const CombatReplaySnapshotSystem = preload("res://combat_replay_snapshot_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_combat_replay_snapshot_parity (Direction 4: Combat Highlights 1:1) ===")
_test_combat_session_tracking()
_test_highlight_card_generation_and_rating()
_test_personal_bests_and_records()
_test_history_buffer_cap()
_finish()
func _test_combat_session_tracking() -> void:
print("\n--- Test 1: Session Tracking & Hit Metrics ---")
var cr := CombatReplaySnapshotSystem.new()
var start_sig := {"fired": false, "name": ""}
cr.combat_session_started.connect(func(n: String):
start_sig["fired"] = true
start_sig["name"] = n
)
var s_res = cr.start_combat_session(1901, "九尾妖狐", 280000)
_assert(s_res["ok"] == true, "Session started")
_assert(cr.is_in_session == true, "is_in_session is true")
_assert(start_sig["fired"] == true and start_sig["name"] == "九尾妖狐", "combat_session_started emitted")
# Record attacks
cr.record_hit(1500, false)
cr.record_hit(3000, true) # Crit
cr.record_hit(8500, true, "三连斩") # Skill crit, highest hit so far
cr.record_damage_taken(650)
_assert(cr.total_damage_dealt == 13000, "Total damage dealt is 13000 (1500 + 3000 + 8500)")
_assert(cr.total_attacks == 3, "Total attacks is 3")
_assert(cr.critical_hits_count == 2, "2 critical hits")
_assert(cr.total_skills_used == 1, "1 skill used")
_assert(cr.max_single_hit == 8500, "Highest single hit tracked as 8500")
_assert(cr.total_damage_taken == 650, "Damage taken tracked as 650")
func _test_highlight_card_generation_and_rating() -> void:
print("\n--- Test 2: Highlight Card Generation & S-Rank Rating ---")
var cr := CombatReplaySnapshotSystem.new()
cr.start_combat_session(1304, "黄虎领主", 320000)
var card_sig := {"fired": false, "rank": ""}
cr.combat_highlight_generated.connect(func(c: Dictionary):
card_sig["fired"] = true
card_sig["rank"] = c["rank"]
)
# Simulate 10 seconds of combat with 50,000 total damage (DPS = 5000 -> S Rank)
cr.update(10.0)
cr.record_hit(20000, true, "旋风斩")
cr.record_hit(30000, true, "剑气斩")
var drops: Array = [{"vnum": 50513, "name": "灵魂之石", "count": 1}]
var card = cr.end_combat_session(true, drops)
_assert(cr.is_in_session == false, "Session ended")
_assert(card["target_name"] == "黄虎领主", "Card target name matches")
_assert(card["total_damage"] == 50000, "Card total damage is 50000")
_assert(card["dps"] == 5000, "DPS is 5000 (50000 / 10s)")
_assert(card["rank"] == "S", "Awarded S Rank (DPS >= 4000)")
_assert(card["drops"].size() == 1, "Drops included in highlight card")
_assert(card_sig["fired"] == true and card_sig["rank"] == "S", "combat_highlight_generated signal fired")
func _test_personal_bests_and_records() -> void:
print("\n--- Test 3: Personal Best Records & Signals ---")
var cr := CombatReplaySnapshotSystem.new()
var record_sig := {"fired": false, "type": "", "val": 0}
cr.new_personal_record.connect(func(_t: String, rtype: String, val: int):
record_sig["fired"] = true
record_sig["type"] = rtype
record_sig["val"] = val
)
# 1st Kill: Nine Tails, 10s, 30000 dmg, DPS = 3000, max hit = 10000
cr.start_combat_session(1901, "九尾妖狐", 280000)
cr.update(10.0)
cr.record_hit(10000, true)
cr.record_hit(20000, true)
cr.end_combat_session(true)
_assert(record_sig["fired"] == true and record_sig["type"] == "FIRST_KILL", "First kill record emitted")
var pb1 = cr.get_personal_best("九尾妖狐")
_assert(pb1["best_dps"] == 3000, "Recorded best DPS 3000")
_assert(pb1["highest_hit"] == 20000, "Recorded highest hit 20000")
# 2nd Kill: Nine Tails, faster kill (5s), DPS = 8000, max hit = 35000
record_sig["fired"] = false
cr.start_combat_session(1901, "九尾妖狐", 280000)
cr.update(5.0)
cr.record_hit(35000, true, "大绝招")
cr.record_hit(5000, false)
cr.end_combat_session(true)
_assert(record_sig["fired"] == true, "New personal record emitted")
var pb2 = cr.get_personal_best("九尾妖狐")
_assert(pb2["best_dps"] == 8000, "Best DPS updated to 8000")
_assert(pb2["highest_hit"] == 35000, "Highest hit updated to 35000")
_assert(pb2["fastest_time"] == 5.0, "Fastest time updated to 5.0s")
func _test_history_buffer_cap() -> void:
print("\n--- Test 4: History Buffer Cap (Max 20 Cards) ---")
var cr := CombatReplaySnapshotSystem.new()
for i in range(25):
cr.start_combat_session(1, "Mob_%d" % i, 100)
cr.update(1.0)
cr.record_hit(100, false)
cr.end_combat_session(true)
var recents = cr.get_recent_highlights()
_assert(recents.size() == CombatReplaySnapshotSystem.MAX_STORED_CARDS, "History capped at max 20 cards")
_assert(recents[0]["target_name"] == "Mob_24", "Most recent card is at front")
func _finish() -> void:
print("\n==========================================")
print("Combat Replay Snapshot Parity Tests Finished:")
print("Passed: %d, Failed: %d" % [_passed, _failed])
print("==========================================")
if _failed > 0:
printerr("FAILED: Some tests did not pass.")
quit(1)
else:
print("SUCCESS: All Combat Replay Snapshot parity tests passed!")
quit(0)