Files
mtgodot-poc/project/test_event_manager_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

144 lines
5.3 KiB
GDScript

# test_event_manager_parity.gd —— 40250 全服掉落活动与倍率调度器 1:1 纯净回归测试套件
extends SceneTree
const EventManagerSystem = preload("res://event_manager_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_event_manager_parity (Direction 4: Solo Event Manager 1:1) ===")
_test_rate_adjustments()
_test_event_toggling()
_test_event_drop_chances()
_test_box_opening()
_finish()
func _test_rate_adjustments() -> void:
print("\n--- Test 1: Rate Adjustments (EXP, Drop, Yang) ---")
var ems := EventManagerSystem.new()
# Invalid multipliers
var r_bad1 = ems.set_rate("exp", 0.5)
_assert(r_bad1["ok"] == false and r_bad1["reason"] == "INVALID_MULTIPLIER", "< 1.0 multiplier rejected")
var r_bad2 = ems.set_rate("exp", 10.0)
_assert(r_bad2["ok"] == false and r_bad2["reason"] == "INVALID_MULTIPLIER", "> 5.0 multiplier rejected")
var rate_signal := {"fired": false, "type": "", "mult": 0.0}
ems.rate_changed.connect(func(t: String, m: float):
rate_signal["fired"] = true
rate_signal["type"] = t
rate_signal["mult"] = m
)
# 1. EXP Rate 2.0x
var r_exp = ems.set_rate("exp", 2.0)
_assert(r_exp["ok"] == true, "EXP rate set to 2.0x")
_assert(ems.calculate_exp(1000) == 2000, "1000 base EXP doubled to 2000")
_assert(rate_signal["fired"] == true and rate_signal["type"] == "exp", "rate_changed signal fired")
# 2. Gold Rate 3.0x
var r_gold = ems.set_rate("gold", 3.0)
_assert(r_gold["ok"] == true, "Gold rate set to 3.0x")
_assert(ems.calculate_gold(500) == 1500, "500 base Gold tripled to 1500")
# 3. Drop Rate 1.5x
var r_drop = ems.set_rate("drop", 1.5)
_assert(r_drop["ok"] == true, "Drop rate set to 1.5x")
_assert(ems.drop_rate == 1.5, "drop_rate is 1.5")
func _test_event_toggling() -> void:
print("\n--- Test 2: Event Toggling (Moonlight & Hexagonal) ---")
var ems := EventManagerSystem.new()
var ev_signal := {"fired": false, "name": "", "active": false}
ems.event_state_changed.connect(func(n: String, act: bool):
ev_signal["fired"] = true
ev_signal["name"] = n
ev_signal["active"] = act
)
# Invalid event
var r_bad = ems.toggle_event("christmas", true)
_assert(r_bad["ok"] == false and r_bad["reason"] == "INVALID_EVENT_NAME", "Invalid event name rejected")
# Toggle Moonlight event ON
var r1 = ems.toggle_event("moonlight", true)
_assert(r1["ok"] == true and ems.is_moonlight_active == true, "Moonlight event enabled")
_assert(ev_signal["fired"] == true and ev_signal["name"] == "moonlight" and ev_signal["active"] == true, "event_state_changed signal fired")
# Toggle Hexagonal event ON
var r2 = ems.toggle_event("hexagonal", true)
_assert(r2["ok"] == true and ems.is_hexagonal_active == true, "Hexagonal event enabled")
# Toggle Moonlight event OFF
ems.toggle_event("moonlight", false)
_assert(ems.is_moonlight_active == false, "Moonlight event disabled")
func _test_event_drop_chances() -> void:
print("\n--- Test 3: Event Box Drops on Mob Kills ---")
var ems := EventManagerSystem.new()
ems.toggle_event("moonlight", true)
ems.toggle_event("hexagonal", true)
var drop_signal := {"fired": false, "vnum": 0}
ems.event_box_dropped.connect(func(v: int, _n: String):
drop_signal["fired"] = true
drop_signal["vnum"] = v
)
# 1. Level difference > 15 (Mob Lv 10 vs Player Lv 50) -> No drop
var drops_far = ems.check_event_drops(10, 50, 0.01)
_assert(drops_far.is_empty(), "Level diff > 15 drops nothing")
# 2. Level difference <= 15 with winning rolls
# Moonlight chance = 10% (0.10). Forced roll = 0.05 -> drops 50011
# Hexagonal chance = 15% (0.15). Forced roll = 0.05 -> drops 50037
var drops = ems.check_event_drops(50, 52, 0.05)
_assert(drops.size() == 2, "Both Moonlight and Hexagonal boxes dropped on winning roll")
_assert(drops[0]["vnum"] == EventManagerSystem.ITEM_MOONLIGHT_BOX, "Moonlight Box (50011) dropped")
_assert(drops[1]["vnum"] == EventManagerSystem.ITEM_HEXAGONAL_BOX, "Hexagonal Box (50037) dropped")
_assert(drop_signal["fired"] == true, "event_box_dropped signal fired")
# 3. Losing roll (e.g. 0.80) -> No drop
var drops_fail = ems.check_event_drops(50, 52, 0.80)
_assert(drops_fail.is_empty(), "Losing roll drops nothing")
func _test_box_opening() -> void:
print("\n--- Test 4: Event Box Opening (50011 Loot Pool) ---")
var ems := EventManagerSystem.new()
var inv: Array = [
{"vnum": EventManagerSystem.ITEM_MOONLIGHT_BOX, "name": "月光宝盒", "count": 1},
null
]
# Open Moonlight Box at slot 0
var res = ems.open_event_box(0, inv)
_assert(res["ok"] == true, "Moonlight box opened successfully")
var reward = res["reward"]
_assert(reward.has("vnum") and reward.has("name"), "Valid reward drawn from pool")
print(" Drew Moonlight Box reward: %s (vnum: %d)" % [reward["name"], reward["vnum"]])
var stored_slot = res["stored_slot"]
_assert(stored_slot >= 0 and inv[stored_slot] != null, "Reward saved in inventory")
_assert(inv[stored_slot]["vnum"] == reward["vnum"], "Inventory item matches reward")
func _finish() -> void:
print("\n==========================================")
print("Event Manager Parity Test Results: %d Passed, %d Failed" % [_passed, _failed])
print("==========================================")
if _failed > 0:
quit(1)
else:
quit(0)