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:
+29
-2
@@ -50,8 +50,11 @@ class FakePC extends Node:
|
||||
var server_speed := 1.0
|
||||
var walk_calls := []
|
||||
var frozen := false
|
||||
var going := false
|
||||
func set_server_speed(moving_speed: int) -> void: server_speed = float(moving_speed) / 100.0
|
||||
func walk_to(p: Vector3) -> void: walk_calls.append(p)
|
||||
func walk_to(p: Vector3) -> void: walk_calls.append(p); going = true
|
||||
func is_going() -> bool: return going
|
||||
func stop() -> void: going = false
|
||||
|
||||
class FakeHud extends Node:
|
||||
var vitals := []
|
||||
@@ -126,7 +129,7 @@ func _run() -> void:
|
||||
pc.player.rotation.y = 0.0
|
||||
fc.calls.fishing.clear()
|
||||
np.set_attack_key(true)
|
||||
_ck(fc.calls.fishing.size() == 1 and is_equal_approx(float(fc.calls.fishing[0]), 270.0),
|
||||
_ck(fc.calls.fishing.size() == 1 and is_equal_approx(float(fc.calls.fishing[0]), 0.0),
|
||||
"fishing attack key -> CG_FISHING with MapCoord heading")
|
||||
_ck(not np._attack_key_down, "fishing attack key does not enable normal attack")
|
||||
fc.fishing_event.emit(0, 1000, 0)
|
||||
@@ -173,10 +176,34 @@ func _run() -> void:
|
||||
# 窗口由服务端 cube_open 命令打开前的入口。
|
||||
var npc := Node3D.new()
|
||||
npc.set_meta("vid", 3000)
|
||||
npc.position = Vector3(4, 0, -5) # 距玩家(3.3,0,-5) 0.7m -> 交互距离内(<= 5m)
|
||||
root.add_child(npc)
|
||||
nw._by_vid[3000] = npc
|
||||
fc.ents[3000] = {"vid": 3000, "ch_type": 1, "name": "Cube NPC", "pos": npc.position}
|
||||
pc.target_selected.emit(npc)
|
||||
_ck(fc.calls.click_npc == [3000], "NPC selection -> click_npc(3000)")
|
||||
|
||||
# 远距离点选 NPC(> 5m):预约走近,到达交互距离后停下并触发 click_npc
|
||||
var far_npc := Node3D.new()
|
||||
far_npc.set_meta("vid", 3010)
|
||||
far_npc.position = Vector3(20, 0, -5) # 距玩家 16.7m -> 超出 5m 交互范围
|
||||
root.add_child(far_npc)
|
||||
nw._by_vid[3010] = far_npc
|
||||
fc.ents[3010] = {"vid": 3010, "ch_type": 1, "name": "Far NPC", "pos": far_npc.position}
|
||||
pc.target_selected.emit(far_npc)
|
||||
_ck(np._reserved_mode == 2, "远距离点 NPC -> 预约走近 (CLICK_ACTOR)")
|
||||
_ck(pc.is_going(), "远距离点 NPC -> 角色自动向 NPC 移动")
|
||||
_ck(fc.calls.click_npc == [3000], "尚未到达时不发点击包")
|
||||
# 玩家走近到 NPC 交互距离内
|
||||
pc.player.position = Vector3(18, 0, -5)
|
||||
np._reserve_process_click_actor()
|
||||
_ck(fc.calls.click_npc == [3000, 3010], "走近到交互距离后 -> 触发 click_npc(3010)")
|
||||
_ck(np._reserved_mode == 0, "触发交互后清空预约")
|
||||
_ck(not pc.is_going(), "触发交互后停止移动")
|
||||
nw._by_vid.erase(3010)
|
||||
fc.ents.erase(3010)
|
||||
far_npc.queue_free()
|
||||
pc.player.position = Vector3(3.3, 0, -5)
|
||||
# §5.4 / §8.8:木门不应退化为 PC;它可进入 CanViewTargetHP / 攻击分类。
|
||||
_ck(np._entity_kind({"vid": 3001, "race": 13000}) == EntityRules.KIND_WOODEN_DOOR,
|
||||
"race 13000 -> WOODEN_DOOR")
|
||||
|
||||
Reference in New Issue
Block a user