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 客户端对拍缺陷发现与修复工程指南
This commit is contained in:
@@ -63,6 +63,9 @@ func _run() -> void:
|
||||
if hair_image != null:
|
||||
hair_image.save_png(output.path_join("hair-texture.png"))
|
||||
var mesh_bounds: Array = []
|
||||
var body_uses_blue_steel_skin := false
|
||||
var blue_steel_path := AssetRoot.path().path_join("patch2/ymir work/pc/warrior/warrior_4-2.dds")
|
||||
var blue_steel_image: Image = ua.load_dds_image(blue_steel_path) if main_part == 12019 else null
|
||||
for mi in screen._pv.find_children("*", "MeshInstance3D", true, false):
|
||||
var local_aabb: AABB = mi.get_aabb()
|
||||
var world_aabb: AABB = mi.get_global_transform() * local_aabb
|
||||
@@ -78,6 +81,17 @@ func _run() -> void:
|
||||
var mat: Material = mi.get_active_material(surface)
|
||||
if mat is ShaderMaterial:
|
||||
print("MATERIAL mode=", mat.get_shader_parameter("mode"), " alpha_write=", mat.shader.code.contains("ALPHA ="))
|
||||
var albedo := mat.get_shader_parameter("albedo_tex") as Texture2D
|
||||
if albedo and blue_steel_image:
|
||||
var actual := albedo.get_image()
|
||||
# Character textures generate mipmaps before upload. Compare only
|
||||
# level 0 with the decoded DDS or identical pixels would differ by
|
||||
# the appended mip levels.
|
||||
var expected_data := blue_steel_image.get_data()
|
||||
var actual_data := actual.get_data() if actual else PackedByteArray()
|
||||
if actual and actual.get_size() == blue_steel_image.get_size() \
|
||||
and actual_data.slice(0, expected_data.size()) == expected_data:
|
||||
body_uses_blue_steel_skin = true
|
||||
if "--solid-body" in OS.get_cmdline_user_args():
|
||||
var solid := StandardMaterial3D.new()
|
||||
solid.albedo_texture = mat.get_shader_parameter("albedo_tex")
|
||||
@@ -87,12 +101,23 @@ func _run() -> void:
|
||||
printerr("FAIL: server armor was not applied")
|
||||
quit(1)
|
||||
return
|
||||
if main_part == 12019 and not body_uses_blue_steel_skin:
|
||||
printerr("FAIL: armor 12019 geometry loaded without warrior_4-2 target skin")
|
||||
quit(1)
|
||||
return
|
||||
if hair_part == 1001 and not String(screen._pv.model.get("hair_gr2")).to_lower().contains("hair_2_1"):
|
||||
printerr("FAIL: standard HairIndex 1001 did not replace the default hair model")
|
||||
quit(1)
|
||||
return
|
||||
if DisplayServer.get_name() != "headless":
|
||||
await RenderingServer.frame_post_draw
|
||||
if screen._viewport:
|
||||
var viewport_image := screen._viewport.get_texture().get_image()
|
||||
if viewport_image.detect_alpha() != Image.ALPHA_NONE:
|
||||
printerr("FAIL: selection stage must be opaque; transparent additive particles create black quads")
|
||||
quit(1)
|
||||
return
|
||||
viewport_image.save_png(output.path_join("viewport.png"))
|
||||
if root.get_texture().get_image().save_png(output.path_join("selection.png")) != OK:
|
||||
quit(1)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user