完善客户端功能并同步差距文档
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# DungeonState —— GC_DUNGEON 目的地状态(40250/ClientVS22)。
|
||||
#
|
||||
# 参考端 PythonNetworkStreamPhaseGame.cpp:3875-3901 收到目的地后调用
|
||||
# CPythonPlayer::SetDungeonDestinationPosition;PythonPlayer.cpp:147-167、
|
||||
# :1255-1285 保存全局像素/厘米坐标、立即提示,并在接近目标后清除,未到达时
|
||||
# 每 20 秒再次提示。本工程把目标状态与 UI 解耦,UI 只消费信号。
|
||||
extends Node
|
||||
|
||||
signal destination_changed(active: bool, world_pos: Vector3)
|
||||
signal destination_reached(world_pos: Vector3)
|
||||
signal alarm_requested(world_pos: Vector3)
|
||||
|
||||
const TIME_ATTACK_START := 0
|
||||
const DESTINATION_POSITION := 1
|
||||
const ARRIVAL_THRESHOLD_CM := 10000.0
|
||||
const ALARM_INTERVAL_SEC := 20.0
|
||||
|
||||
var client: Node
|
||||
var player_getter: Callable
|
||||
var active := false
|
||||
var destination_cm := Vector2.ZERO
|
||||
var destination_world := Vector3.ZERO
|
||||
var last_subheader := -1
|
||||
var alarm_count := 0
|
||||
var _last_alarm_ms := -1
|
||||
|
||||
func setup(m2client: Node, get_player: Callable) -> void:
|
||||
client = m2client
|
||||
player_getter = get_player
|
||||
if client and client.has_signal("dungeon_event"):
|
||||
client.dungeon_event.connect(_on_dungeon_event)
|
||||
if client and client.has_signal("world_reset"):
|
||||
client.world_reset.connect(clear)
|
||||
|
||||
func _on_dungeon_event(subheader: int, x: int, y: int, has_destination: bool) -> void:
|
||||
last_subheader = subheader
|
||||
# ClientVS22's TIME_ATTACK_START branch is intentionally empty. Consume the
|
||||
# packet but do not invent a local timer that the reference client does not run.
|
||||
if subheader != DESTINATION_POSITION or not has_destination:
|
||||
return
|
||||
destination_cm = Vector2(float(x), float(y))
|
||||
# GC_DUNGEON carries TPixelPosition x/y in global server centimetres. The
|
||||
# network frame uses -Y for Godot Z before MapCoord applies the map base.
|
||||
destination_world = MapCoord.to_world(Vector3(float(x) * 0.01, 0.0, -float(y) * 0.01))
|
||||
active = true
|
||||
_last_alarm_ms = -1
|
||||
destination_changed.emit(true, destination_world)
|
||||
_alarm()
|
||||
|
||||
func clear() -> void:
|
||||
var was_active := active
|
||||
active = false
|
||||
destination_cm = Vector2.ZERO
|
||||
destination_world = Vector3.ZERO
|
||||
_last_alarm_ms = -1
|
||||
if was_active:
|
||||
destination_changed.emit(false, Vector3.ZERO)
|
||||
|
||||
func _player() -> Node3D:
|
||||
if not player_getter.is_valid():
|
||||
return null
|
||||
var p: Variant = player_getter.call()
|
||||
return p as Node3D
|
||||
|
||||
func _alarm() -> void:
|
||||
_last_alarm_ms = Time.get_ticks_msec()
|
||||
alarm_count += 1
|
||||
alarm_requested.emit(destination_world)
|
||||
|
||||
func _process(_dt: float) -> void:
|
||||
if not active:
|
||||
return
|
||||
var p := _player()
|
||||
if p:
|
||||
# Match PythonPlayer.cpp:155: integer Manhattan distance, not Euclidean.
|
||||
var p_cm := MapCoord.to_server_cm(p.global_position)
|
||||
var distance_cm := absf(p_cm.x - destination_cm.x) + absf(p_cm.y - destination_cm.y)
|
||||
if distance_cm < ARRIVAL_THRESHOLD_CM:
|
||||
var reached := destination_world
|
||||
active = false
|
||||
destination_changed.emit(false, reached)
|
||||
destination_reached.emit(reached)
|
||||
return
|
||||
var now := Time.get_ticks_msec()
|
||||
if _last_alarm_ms < 0 or now - _last_alarm_ms > int(ALARM_INTERVAL_SEC * 1000.0):
|
||||
_alarm()
|
||||
Reference in New Issue
Block a user