- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
100 lines
3.6 KiB
GDScript
100 lines
3.6 KiB
GDScript
# 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=770,z=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)
|