- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
120 lines
4.4 KiB
GDScript
120 lines
4.4 KiB
GDScript
# test_atlas_navigation_parity.gd —— 40250 全景大地图与寻路导航回归测试
|
|
extends SceneTree
|
|
|
|
const SystemClass = preload("res://atlas_navigation_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_atlas_navigation_parity (Batch 28 Direction 1) ===")
|
|
_test_atlas_toggle_and_map_registry()
|
|
_test_zoom_and_pan_controls()
|
|
_test_npc_directory_indexing()
|
|
_test_signal_point_and_navigation_vector()
|
|
_test_coordinate_projection()
|
|
|
|
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_atlas_toggle_and_map_registry() -> void:
|
|
print("\n--- Test 1: M Key Toggle & Map Registry ---")
|
|
var nav = SystemClass.new("metin2_map_a1")
|
|
|
|
_assert(nav.is_atlas_visible == false, "Atlas initially hidden")
|
|
|
|
# Toggle M
|
|
var state1 = nav.toggle_atlas()
|
|
_assert(state1 == true and nav.is_atlas_visible == true, "Atlas toggled open on M key")
|
|
|
|
var state2 = nav.toggle_atlas()
|
|
_assert(state2 == false and nav.is_atlas_visible == false, "Atlas toggled closed on second M key")
|
|
|
|
# Map switching
|
|
var sw_ok = nav.set_map("metin2_map_milgyo")
|
|
_assert(sw_ok == true, "Switched map to metin2_map_milgyo")
|
|
var info = nav.get_current_map_info()
|
|
_assert(info["name"] == "幽冥神殿 (Dark Temple)", "Map registry metadata correctly fetched")
|
|
|
|
var sw_fail = nav.set_map("invalid_map_id")
|
|
_assert(sw_fail == false, "Reject invalid map id")
|
|
|
|
func _test_zoom_and_pan_controls() -> void:
|
|
print("\n--- Test 2: Zoom and Pan Clamping ---")
|
|
var nav = SystemClass.new()
|
|
|
|
# Zoom clamping (0.5 to 3.0)
|
|
nav.set_zoom(0.2)
|
|
_assert(nav.zoom_level == 0.5, "Zoom clamped at lower bound 0.5x")
|
|
|
|
nav.set_zoom(5.0)
|
|
_assert(nav.zoom_level == 3.0, "Zoom clamped at upper bound 3.0x")
|
|
|
|
nav.set_zoom(1.5)
|
|
_assert(nav.zoom_level == 1.5, "Zoom set to 1.5x")
|
|
|
|
# Pan accumulation
|
|
nav.apply_pan(Vector2(20, -10))
|
|
_assert(nav.pan_offset == Vector2(20, -10), "Pan offset accumulated")
|
|
|
|
func _test_npc_directory_indexing() -> void:
|
|
print("\n--- Test 3: NPC Directory Indexing & Filtering ---")
|
|
var nav = SystemClass.new()
|
|
|
|
var all_npcs = nav.get_npcs()
|
|
_assert(all_npcs.size() >= 10, "Default town contains at least 10 key NPCs")
|
|
|
|
var smiths = nav.get_npcs("Smith")
|
|
_assert(smiths.size() == 1 and smiths[0]["vid"] == 20016, "Filtered single blacksmith (VID 20016)")
|
|
|
|
var shops = nav.get_npcs("Shop")
|
|
_assert(shops.size() == 3, "Filtered 3 shops (Weapon, Armor, General)")
|
|
|
|
var bio = nav.find_npc_by_vid(20084)
|
|
_assert(bio.get("name").contains("生物学家"), "Found Biologist by VID 20084")
|
|
|
|
func _test_signal_point_and_navigation_vector() -> void:
|
|
print("\n--- Test 4: Signal Point Waypoint & Compass Bearing ---")
|
|
var nav = SystemClass.new()
|
|
|
|
# Add signal waypoint
|
|
var sig = nav.add_signal_point(600, 600)
|
|
_assert(nav.signal_points.size() == 1, "Signal waypoint added")
|
|
_assert(sig["x"] == 600 and sig["y"] == 600, "Signal waypoint coordinates match (600, 600)")
|
|
|
|
# Calculate compass bearing: Player at (500, 600) -> Target at (600, 600)
|
|
var nav_vec = nav.calculate_navigation_vector(Vector2(500, 600), Vector2(600, 600))
|
|
_assert(nav_vec["distance"] == 100.0, "Distance is exactly 100")
|
|
_assert(is_equal_approx(nav_vec["angle_deg"], 0.0), "Heading is exactly 0 degrees (East)")
|
|
_assert(nav_vec["arrived"] == false, "Not arrived (dist 100 > 30)")
|
|
|
|
# Arrival test: Player at (590, 600) -> Target at (600, 600)
|
|
var nav_arrived = nav.calculate_navigation_vector(Vector2(590, 600), Vector2(600, 600))
|
|
_assert(nav_arrived["distance"] == 10.0, "Distance is 10")
|
|
_assert(nav_arrived["arrived"] == true, "Arrival detected when dist <= 30")
|
|
|
|
# Clear all signals
|
|
nav.clear_all_signals()
|
|
_assert(nav.signal_points.is_empty(), "All signal waypoints cleared")
|
|
|
|
func _test_coordinate_projection() -> void:
|
|
print("\n--- Test 5: World to Atlas UI Coordinate Projection ---")
|
|
var nav = SystemClass.new("metin2_map_a1") # 4000x4000 world -> 256x256 atlas
|
|
nav.set_zoom(1.0)
|
|
|
|
# World center (2000, 2000) -> Atlas center (128, 128)
|
|
var projected = nav.world_to_atlas_coord(Vector2(2000, 2000))
|
|
_assert(is_equal_approx(projected.x, 128.0) and is_equal_approx(projected.y, 128.0), "Projected world center (2000, 2000) to atlas (128, 128)")
|