Complete remaining client gap features

This commit is contained in:
shenlei
2026-09-04 13:25:05 +09:00
parent 13ccb8d02d
commit 9a4a044da5
47 changed files with 6667 additions and 140 deletions
+76
View File
@@ -6,6 +6,7 @@ extends SceneTree
const NetPlay = preload("res://net_play.gd")
const NetWorld = preload("res://net_world.gd")
const EntityRules = preload("res://entity_rules.gd")
class FakeClient extends Node:
signal entity_spawned(entity: Dictionary)
@@ -176,6 +177,11 @@ func _run() -> void:
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)")
# §5.4 / §8.8:木门不应退化为 PC;它可进入 CanViewTargetHP / 攻击分类。
_ck(np._entity_kind({"vid": 3001, "race": 13000}) == EntityRules.KIND_WOODEN_DOOR,
"race 13000 -> WOODEN_DOOR")
_ck(np._entity_kind({"vid": 3002, "kind": EntityRules.KIND_BUILDING}) == EntityRules.KIND_BUILDING,
"explicit BUILDING kind -> BUILDING")
# 5) 只有按住 SPACE(参考端 m_isAtkKey)才在攻击距离内 attack
np.set_attack_key(true)
@@ -381,6 +387,76 @@ func _run() -> void:
fc.target_info.emit(2000, 40)
_ck(hud.target.size() == 2 and hud.target[1] == 40, "hud.set_target(pct=40)")
# 8b) §8.4「看他国玩家目标框」前置过滤(uitarget.py:189-193 / target_board.hidden_as_other_empire
fc.ents[1000]["empire"] = 1
fc.ents[2500] = {"vid": 2500, "ch_type": 0, "name": "Enemy", "empire": 2,
"pos": Vector3(5, 0, 5), "hp": 100, "max_hp": 100, "dead": false}
# 开关开(默认 true):异阵营 PC 目标框照旧走 CLOSE_IF_DIFFERENT,框上正是该 VID -> 保留
np._target_vid = 2500
fc.target_info.emit(2500, 60)
_ck(np._target_vid == 2500, "看他国框开 -> 异阵营 PC 目标框保留")
# 开关关:异阵营 PC -> 前置过滤直接清目标框
var cleared_n: int = hud.cleared
np.set_view_other_empire_target(false)
np._target_vid = 2500
fc.target_info.emit(2500, 60)
_ck(np._target_vid == 0 and hud.cleared == cleared_n + 1, "看他国框关 -> 异阵营 PC 目标框被前置过滤清掉")
# 开关关不影响怪(empire 0 -> IsSameEmpire 为真)
np._target_vid = 0
fc.target_info.emit(2000, 30)
_ck(hud.target[1] == 30 and np._target_vid == 2000, "看他国框关不影响怪目标(HP 血条照设)")
np.set_view_other_empire_target(true)
fc.ents[1000].erase("empire")
fc.ents.erase(2500)
# 收尾:_target_vid 落在 2000(与原 8 一致),供 9) 目标死亡清框
# 8c) seam ⑫ 收口 —— game.py SetPCTargetBoard :804targetBoard.Open 之后,若按住
# LCONTROL:807)且同阵营(:809 IsSameEmpire)且非本人(:812)且非 building
# :814-> interface.OpenWhisperDialog(name)。poc 侧 net_play 发 whisper_requested
# game_scene 接到 chat.start_whisper()。C++ 只对 PC 分派 SetPCTargetBoard。
var whispers: Array = []
np.whisper_requested.connect(func(nm: String): whispers.append(nm))
fc.ents[1000]["empire"] = 1
var bob := Node3D.new()
bob.set_meta("vid", 6100)
bob.position = Vector3(4, 0, -5)
root.add_child(bob)
nw._by_vid[6100] = bob
fc.ents[6100] = {"vid": 6100, "ch_type": 0, "name": "Bob", "empire": 1,
"pos": bob.position, "hp": 100, "max_hp": 100, "dead": false}
# LCONTROL 没按住 -> 只普通选中,不开悄悄话
np._target_vid = 0
np.set_lcontrol_down(false)
pc.target_selected.emit(bob)
_ck(whispers.is_empty(), "无 LCONTROL 点 PC -> 不开悄悄话")
_ck(fc.calls.set_target.back() == 6100, "点 PC 仍照常选中(set_target 6100")
# 按住 LCONTROL + 同阵营他人 PC -> whisper_requested("Bob")
np.set_lcontrol_down(true)
pc.target_selected.emit(bob)
_ck(whispers == ["Bob"], "LCONTROL 点同阵营他人 PC -> whisper_requested('Bob')")
# 异阵营 PC -> 不请求(:809 IsSameEmpire
whispers.clear()
fc.ents[6100]["empire"] = 2
pc.target_selected.emit(bob)
_ck(whispers.is_empty(), "LCONTROL 点异阵营 PC -> 不开悄悄话")
fc.ents[6100]["empire"] = 1
# 怪(KIND_MONSTER)即使按住 LCONTROL 也不走(C++ 只对 PC 分派 SetPCTargetBoard
whispers.clear()
var wolf2 := Node3D.new()
wolf2.set_meta("vid", 6200)
wolf2.position = Vector3(4, 0, -5)
root.add_child(wolf2)
nw._by_vid[6200] = wolf2
fc.ents[6200] = {"vid": 6200, "ch_type": 2, "name": "Wolf2", "empire": 0,
"pos": wolf2.position, "hp": 50, "max_hp": 50, "dead": false}
pc.target_selected.emit(wolf2)
_ck(whispers.is_empty(), "LCONTROL 点怪 -> 不开悄悄话(仅 PC 分派)")
np.set_lcontrol_down(false)
fc.ents[1000].erase("empire")
fc.ents.erase(6100); fc.ents.erase(6200)
nw._by_vid.erase(6100); nw._by_vid.erase(6200)
np._target_vid = 2000 # 复位到 8b 收尾态,供 9) 目标死亡清框
# 9) 目标死亡 -> 清目标
fc.ents[2000]["dead"] = true
fc.entity_dead.emit(2000)