- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
124 lines
5.5 KiB
GDScript
124 lines
5.5 KiB
GDScript
# test_client_phase_integration_parity.gd —— 40250 客户端全状态机一体化回归测试
|
|
extends SceneTree
|
|
|
|
const SystemClass = preload("res://client_phase_integration_system.gd")
|
|
|
|
var _passed: int = 0
|
|
var _failed: int = 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_client_phase_integration_parity (Batch 30 Direction 3) ===")
|
|
_test_fresh_account_full_lifecycle_flow()
|
|
_test_existing_account_direct_select_flow()
|
|
_test_in_game_hotkey_and_focus_stack()
|
|
_test_logout_transitions()
|
|
|
|
print("\n=== Result: %d Passed, %d Failed ===" % [_passed, _failed])
|
|
if _failed == 0:
|
|
print("ALL TESTS PASSED!\n")
|
|
else:
|
|
printerr("SOME TESTS FAILED!\n")
|
|
quit(0 if _failed == 0 else 1)
|
|
|
|
func _test_fresh_account_full_lifecycle_flow() -> void:
|
|
print("\n--- Test 1: Fresh Account Full Lifecycle (Login -> Empire -> Create -> Select -> Loading -> Game) ---")
|
|
var client = SystemClass.new()
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_LOGIN, "Starts in PHASE_LOGIN")
|
|
|
|
# Register temporary fresh account
|
|
client.login_phase.registered_accounts["newbie"] = { "password": "123", "has_characters": false }
|
|
|
|
# 1. Login
|
|
var r_log = client.process_login("newbie", "123")
|
|
_assert(r_log["success"] == true, "Login succeeded")
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_EMPIRE, "Transitions to PHASE_EMPIRE for new account")
|
|
|
|
# 2. Select Empire (Jinno = 3)
|
|
var r_emp = client.process_empire_select(3)
|
|
_assert(r_emp["success"] == true, "Empire selection confirmed")
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_CREATE, "Transitions to PHASE_CREATE")
|
|
|
|
# 3. Create Character
|
|
var r_cr = client.process_character_create("NewKnight", 3)
|
|
_assert(r_cr["success"] == true, "Created NewKnight successfully")
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_SELECT, "Transitions to PHASE_SELECT")
|
|
|
|
# 4. Start Game
|
|
var r_st = client.process_character_start(0)
|
|
_assert(r_st["success"] == true, "Started game from slot 0")
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_GAME, "Transitions through Loading to PHASE_GAME")
|
|
_assert(client.active_character["name"] == "NewKnight", "Active character is NewKnight")
|
|
_assert(client.jukebox.is_playing == true, "BGM jukebox actively playing in-game music")
|
|
|
|
func _test_existing_account_direct_select_flow() -> void:
|
|
print("\n--- Test 2: Existing Account Direct to Character Select ---")
|
|
var client = SystemClass.new()
|
|
|
|
# Login with existing account (admin has characters)
|
|
var r_log = client.process_login("admin", "password")
|
|
_assert(r_log["success"] == true, "Admin logged in")
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_SELECT, "Existing account transitions directly to PHASE_SELECT")
|
|
|
|
func _test_in_game_hotkey_and_focus_stack() -> void:
|
|
print("\n--- Test 3: In-Game Hotkey Management & Escape Stack ---")
|
|
var client = SystemClass.new()
|
|
client.login_phase.registered_accounts["hero"] = { "password": "123", "has_characters": false }
|
|
client.process_login("hero", "123")
|
|
client.process_empire_select(1)
|
|
client.process_character_create("HeroPlayer", 1)
|
|
client.process_character_start(0)
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_GAME, "In PHASE_GAME")
|
|
|
|
# 1. Alt+M opens Messenger
|
|
var h_msg = client.handle_input_hotkey("Alt+M")
|
|
_assert(h_msg["action"] == "OPEN_MESSENGER", "Alt+M opens messenger")
|
|
_assert(client.dialog_focus_stack.has("MESSENGER"), "MESSENGER pushed to stack")
|
|
|
|
# 2. M opens Atlas
|
|
var h_atlas = client.handle_input_hotkey("M")
|
|
_assert(h_atlas["action"] == "OPEN_ATLAS", "M opens atlas")
|
|
_assert(client.atlas.is_atlas_visible == true, "Atlas is visible")
|
|
_assert(client.dialog_focus_stack[client.dialog_focus_stack.size() - 1] == "ATLAS", "ATLAS on top of stack")
|
|
|
|
# 3. First Escape closes top dialog (ATLAS)
|
|
var esc1 = client.handle_input_hotkey("Escape")
|
|
_assert(esc1["action"] == "CLOSED_TOP_DIALOG" and esc1["dialog"] == "ATLAS", "Escape popped ATLAS")
|
|
_assert(client.atlas.is_atlas_visible == false, "Atlas is hidden")
|
|
|
|
# 4. Second Escape closes MESSENGER
|
|
var esc2 = client.handle_input_hotkey("Escape")
|
|
_assert(esc2["action"] == "CLOSED_TOP_DIALOG" and esc2["dialog"] == "MESSENGER", "Escape popped MESSENGER")
|
|
|
|
# 5. Third Escape on empty stack opens System Menu
|
|
var esc3 = client.handle_input_hotkey("Escape")
|
|
_assert(esc3["action"] == "OPEN_SYSTEM_MENU", "Escape opens System Menu when stack is empty")
|
|
|
|
func _test_logout_transitions() -> void:
|
|
print("\n--- Test 4: Logout Transitions ---")
|
|
var client = SystemClass.new()
|
|
client.login_phase.registered_accounts["user"] = { "password": "123", "has_characters": false }
|
|
client.process_login("user", "123")
|
|
client.process_empire_select(1)
|
|
client.process_character_create("UserChar", 1)
|
|
client.process_character_start(0)
|
|
|
|
# Logout to Select
|
|
client.logout_to_select()
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_SELECT, "Logged out to PHASE_SELECT")
|
|
_assert(client.active_character.is_empty(), "Active character cleared")
|
|
_assert(client.jukebox.current_track == "characterselect.mp3", "Switched BGM to character select theme")
|
|
|
|
# Logout to Login
|
|
client.logout_to_login()
|
|
_assert(client.current_phase == SystemClass.ClientPhase.PHASE_LOGIN, "Logged out to PHASE_LOGIN")
|
|
_assert(client.active_account.is_empty(), "Active account cleared")
|
|
_assert(client.jukebox.current_track == "enter_the_east.mp3", "Switched BGM to login theme")
|