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

100 lines
3.6 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# test_bridge_height_parity.gd
# 验证 40250 规范:桥梁与静态物体 (.mdatr) 高度采样 1:1 对齐测试。
# 验证点:
# 1. 在桥梁所在位置,world.sample_height 返回桥面高度(由 .mdatr 中的 height 网格计算),
# 而不是桥下方河床/水面的裸地形高度。
# 2. 桥梁外侧(偏离桥面)的点,正确回退到裸地形采样高度。
# 3. 角色踏上桥梁时,Y 坐标与桥面高度一致,不再掉落穿透到桥底水下。
extends SceneTree
const ASSETS_PATH := "res://../assets"
const MAP_PATH := "OutdoorA1/metin2_map_a1"
func _init() -> void:
call_deferred("_run")
func _run() -> void:
print("=== Starting test_bridge_height_parity ===")
var world: Node = null
if ClassDB.class_exists("Metin2World"):
world = ClassDB.instantiate("Metin2World")
else:
printerr("FAIL: Metin2World not available")
quit(1)
return
get_root().add_child(world)
var assets_abs := ProjectSettings.globalize_path(ASSETS_PATH)
world.set("assets_root", assets_abs)
world.set("map_path", MAP_PATH)
world.set("objects_enabled", true)
world.set("water_enabled", true)
world.set("load_radius_tiles", -1) # load all chunks
var ok: bool = bool(world.call("load_map"))
if not ok:
printerr("FAIL: load_map failed")
quit(1)
return
# 测试桥梁 1: a1-024-10m-bridge (位于 Chunk 002002)
# 原始 areadata: x=76156.88 y=-59454.84 z=19693.11 bias=-290.0
# Godot 坐标: x = 761.57, z = 594.55
var b1_x := 761.57
var b1_z := 594.55
var h1: float = float(world.call("sample_height", b1_x, b1_z))
print("Bridge 1 (a1-024-10m-bridge) at (%f, %f) sample_height = %f m" % [b1_x, b1_z, h1])
# 桥面应在 205m ~ 207m 区间,而河床地形在 ~198.2m
if h1 < 204.0 or h1 > 208.0:
printerr("FAIL: Bridge 1 deck height expected ~206m, got %f m (fell through to riverbed?)" % h1)
quit(1)
return
print("PASS: Bridge 1 deck height correctly sampled at %f m (> 198.2m riverbed)" % h1)
# 偏离桥面的点 (向河道侧移 15米): (761.57, 570.0) 应为河床高度 ~198m
var off_z := 570.0
var h_off: float = float(world.call("sample_height", b1_x, off_z))
print("Off-bridge riverbed at (%f, %f) sample_height = %f m" % [b1_x, off_z, h_off])
if h_off > 202.0:
printerr("FAIL: Off-bridge point expected riverbed terrain height (< 202m), got %f m" % h_off)
quit(1)
return
print("PASS: Off-bridge point correctly falls back to terrain height %f m" % h_off)
# 测试桥梁 2: general_obj_suspension bridge01 (位于 Chunk 000002)
# 原始 areadata: pos=21390.722656 -70045.242188 13467.375000 rot=roll 270.0
# Godot 坐标: x = 213.91, z = 700.45
var b2_x := 213.91
var b2_z := 700.45
var h2: float = float(world.call("sample_height", b2_x, b2_z))
print("Bridge 2 (suspension bridge01) at (%f, %f) sample_height = %f m" % [b2_x, b2_z, h2])
# 悬索吊桥高度采样验证
if h2 <= 0.0:
printerr("FAIL: Bridge 2 sample_height returned invalid height %f" % h2)
quit(1)
return
print("PASS: Bridge 2 height correctly sampled at %f m" % h2)
# 模拟角色走上桥梁:角色位置沿桥梁中轴线前进
# 桥梁走向从 x=750 到 x=770z=594.55
var step_ok := true
for x_offset in range(-10, 11, 2):
var test_x := b1_x + float(x_offset)
var test_h := float(world.call("sample_height", test_x, b1_z))
if test_h < 203.0:
printerr("FAIL: Character fell through bridge deck at x=%f! height=%f" % [test_x, test_h])
step_ok = false
break
if not step_ok:
quit(1)
return
print("PASS: Character walking along bridge deck maintained deck elevation across entire span!")
world.call("unload_map")
world.queue_free()
print("ALL BRIDGE HEIGHT PARITY CHECKS PASSED (40250 STRICT)")
quit(0)