Files
mtgodot-poc/project/ui/reconnect_ui.gd
T

153 lines
4.5 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ReconnectUI (P10) —— 断线遮罩 + 自动重连倒计时 + 手动重连。
#
# var rc := preload("res://ui/reconnect_ui.gd").new()
# add_child(rc)
# rc.setup(m2client)
#
# `disconnected(reason)` → 显示遮罩 + "N 秒后自动重连";到点调 client.reconnect()。
# `entered_game` 或任何非 offline 的 phase_changed → 隐藏。
# 按钮:立即重连 / 停止(不再自动)。
extends CanvasLayer
const MobileWindowHost := preload("res://ui/mobile/mobile_window_host.gd")
const AUTO_DELAY := 5.0
const MAX_TRIES := 5
var client: Node
var _panel: ColorRect
var _msg: Label
var _count: Label
var _left := 0.0
var _tries := 0
var _auto := true
var _armed := false
var _mobile_mode := false
var _box: VBoxContainer
var _last_viewport_size := Vector2.ZERO
func setup(m2client: Node) -> void:
client = m2client
layer = 70
_build()
if client.has_signal("disconnected"):
client.disconnected.connect(_on_disconnected)
if client.has_signal("entered_game"):
client.entered_game.connect(func(): _dismiss())
if client.has_signal("phase_changed"):
client.phase_changed.connect(func(p):
# Keep the reconnect surface visible while auth/game handshaking is in
# progress. Hiding it on the first "login" phase left players with a
# dead-looking world and no retry feedback on mobile.
if not _armed and String(p).to_lower() not in ["offline", "", "close", "failed"]:
_dismiss())
MobileWindowHost.wire_buttons(self)
set_process(true)
func set_mobile_mode(enabled: bool) -> void:
_mobile_mode = enabled
_apply_layout()
func dismiss() -> void:
_dismiss()
func set_error(reason: String) -> void:
if _msg:
_msg.text = "重连失败:%s" % reason
if _count:
_count.text = "将自动重试"
func is_showing() -> bool:
return _panel.visible
func _on_disconnected(reason: String) -> void:
_msg.text = "连接断开:%s" % reason
_panel.visible = true
_armed = true
_auto = true
_tries = 0
_left = AUTO_DELAY
_apply_layout()
func _dismiss() -> void:
_panel.visible = false
_armed = false
func _retry_now() -> void:
if client == null or not client.has_method("reconnect"):
return
_tries += 1
_count.text = "重连中…(第 %d 次)" % _tries
_left = AUTO_DELAY
var ok: bool = client.reconnect()
if not ok:
_count.text = "重连失败,%0.0f 秒后再试" % AUTO_DELAY
func _process(dt: float) -> void:
_apply_layout()
if not _panel.visible or not _armed:
return
if not _auto:
_count.text = "自动重连已停止"
return
if _tries >= MAX_TRIES:
_count.text = "已重试 %d 次,仍失败" % _tries
return
_left -= dt
_count.text = "%0.0f 秒后自动重连(%d/%d" % [maxf(_left, 0.0), _tries, MAX_TRIES]
if _left <= 0.0:
_retry_now()
func _build() -> void:
_panel = ColorRect.new()
_panel.color = Color(0.05, 0.02, 0.02, 0.92)
_panel.set_anchors_preset(Control.PRESET_FULL_RECT)
_panel.visible = false
add_child(_panel)
var box := VBoxContainer.new()
_box = box
box.set_anchors_preset(Control.PRESET_CENTER)
box.position = Vector2(-160, -70)
box.custom_minimum_size = Vector2(320, 0)
box.add_theme_constant_override("separation", 12)
_panel.add_child(box)
_msg = Label.new()
_msg.text = "连接断开"
_msg.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_msg.add_theme_font_size_override("font_size", 16)
box.add_child(_msg)
_count = Label.new()
_count.text = ""
_count.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
box.add_child(_count)
var row := HBoxContainer.new()
row.alignment = BoxContainer.ALIGNMENT_CENTER
box.add_child(row)
var now_btn := Button.new()
now_btn.text = "立即重连"
now_btn.custom_minimum_size = Vector2(150, 46)
now_btn.pressed.connect(_retry_now)
row.add_child(now_btn)
var stop_btn := Button.new()
stop_btn.text = "停止"
stop_btn.custom_minimum_size = Vector2(120, 46)
stop_btn.pressed.connect(func(): _auto = false)
row.add_child(stop_btn)
func _apply_layout() -> void:
if _panel == null or get_viewport() == null:
return
var viewport_size := get_viewport().get_visible_rect().size
if viewport_size.is_equal_approx(_last_viewport_size) and not _mobile_mode:
return
_last_viewport_size = viewport_size
if not _mobile_mode:
return
var area := MobileWindowHost.safe_rect(get_viewport())
var width := minf(520.0, maxf(300.0, area.size.x - 32.0))
_box.position = area.position + Vector2((area.size.x - width) * 0.5,
(area.size.y - 190.0) * 0.5)
_box.size = Vector2(width, 190.0)
_msg.add_theme_font_size_override("font_size", 18)
_count.add_theme_font_size_override("font_size", 15)