feat: complete mobile UI implementation
This commit is contained in:
+46
-5
@@ -6,7 +6,8 @@
|
||||
# af.start(assets_root) # assets_root 传给 game_scene
|
||||
#
|
||||
# 状态机:LOGIN → SELECT → GAME。M2Client 信号驱动切屏。
|
||||
# 断线:任何阶段都回到登录阶段,和 ClientVS22 的 SetLoginPhase 一致。
|
||||
# 断线:登录/选人阶段回到登录;游戏阶段保留 GameScene,显示重连遮罩,
|
||||
# 重连成功后自动重新进入上次角色,避免短暂闪回选人界面。
|
||||
extends Node
|
||||
|
||||
const ServerInfoRes = preload("res://net/serverinfo.gd")
|
||||
@@ -15,6 +16,8 @@ const LoadingScreen = preload("res://ui/loading_screen.gd")
|
||||
const CharSelectScreen = preload("res://ui/char_select_screen.gd")
|
||||
const GameScene = preload("res://game_scene.gd")
|
||||
const AppLifecycle = preload("res://app_lifecycle.gd")
|
||||
const ReconnectUI = preload("res://ui/reconnect_ui.gd")
|
||||
const UiProfile = preload("res://ui/ui_profile.gd")
|
||||
|
||||
enum { LOGIN, SELECT, GAME }
|
||||
|
||||
@@ -26,12 +29,15 @@ var _ui: CanvasLayer # 登录 / 选人的临时界面层
|
||||
var _loading: CanvasLayer
|
||||
var _game: Node
|
||||
var _lifecycle: Node # 全流程唯一生命周期协调者
|
||||
var _reconnect: Node
|
||||
var build_game_scene := true # 测试里置 false,只跑状态机不建重场景
|
||||
var _sel_server := 0
|
||||
var _sel_channel := 1
|
||||
var _id := OS.get_environment("MT_ACCOUNT")
|
||||
var _pw := OS.get_environment("MT_PASSWORD")
|
||||
var _chars: Array = []
|
||||
var _selected_char_slot := -1
|
||||
var _reconnecting_game := false
|
||||
var _mark_redl_after := 0 # guild-mark re-download cooldown (ticks_msec)
|
||||
# MT_AUTOLOGIN=1:进 LOGIN 自动连接,收到角色列表自动选第一个(冒烟 / CI 用)。
|
||||
var auto_login := OS.get_environment("MT_AUTOLOGIN") == "1" and not _id.is_empty() and not _pw.is_empty()
|
||||
@@ -60,6 +66,11 @@ func start(assets_root: String = "", injected_client: Node = null) -> void:
|
||||
_lifecycle.name = "AppLifecycle"
|
||||
add_child(_lifecycle)
|
||||
_lifecycle.bind(client)
|
||||
_reconnect = ReconnectUI.new()
|
||||
_reconnect.name = "ReconnectUI"
|
||||
add_child(_reconnect)
|
||||
_reconnect.setup(client)
|
||||
_reconnect.set_mobile_mode(UiProfile.resolve() == UiProfile.Mode.MOBILE)
|
||||
_goto_login()
|
||||
if auto_login:
|
||||
call_deferred("_do_connect")
|
||||
@@ -80,6 +91,16 @@ func _wire_client() -> void:
|
||||
|
||||
func _on_char_list(list: Array) -> void:
|
||||
_chars = list
|
||||
if _reconnecting_game:
|
||||
# A full reconnect replays the character list before it can enter the
|
||||
# previous character. Do not briefly replace the live game with SELECT;
|
||||
# re-enter the remembered slot and keep the reconnect mask on screen.
|
||||
var slot := _selected_char_slot
|
||||
if slot < 0 and not _chars.is_empty():
|
||||
slot = int(_chars[0].get("index", 0))
|
||||
if slot >= 0:
|
||||
_enter_character(slot)
|
||||
return
|
||||
# 已在选人页(建号 / 删号后 M2Client 会重发 char_list)——只刷数据,别整屏重建
|
||||
if _state == SELECT and _ui:
|
||||
var sc: Node = _ui.get_node_or_null("CharSelect")
|
||||
@@ -100,6 +121,9 @@ func _on_char_name_changed(pid: int, name: String) -> void:
|
||||
sc.on_char_name_changed(pid, name)
|
||||
|
||||
func _on_entered_game() -> void:
|
||||
_reconnecting_game = false
|
||||
if _reconnect and _reconnect.has_method("dismiss"):
|
||||
_reconnect.dismiss()
|
||||
_goto_game()
|
||||
_start_guild_mark_download()
|
||||
|
||||
@@ -125,12 +149,24 @@ func _on_guild_mark_updated(_guild_id: int, _img_idx: int) -> void:
|
||||
_start_guild_mark_download()
|
||||
|
||||
func _on_login_failed(reason: String) -> void:
|
||||
if _reconnecting_game:
|
||||
if _reconnect and _reconnect.has_method("set_error"):
|
||||
_reconnect.set_error(reason)
|
||||
return
|
||||
if _state != GAME:
|
||||
_goto_login()
|
||||
_set_status("登录失败:%s" % reason)
|
||||
|
||||
func _on_disconnected(reason: String) -> void:
|
||||
if _state == GAME and _game != null and is_instance_valid(_game):
|
||||
_reconnecting_game = true
|
||||
if _reconnect and _reconnect.has_method("set_error"):
|
||||
_reconnect.set_error(reason)
|
||||
return
|
||||
_reconnecting_game = false
|
||||
_goto_login()
|
||||
if _reconnect and _reconnect.has_method("dismiss"):
|
||||
_reconnect.dismiss()
|
||||
_set_status("连接断开:%s" % reason)
|
||||
|
||||
# --- 切屏 ------------------------------------------------------------------
|
||||
@@ -142,6 +178,7 @@ func _clear_ui() -> void:
|
||||
|
||||
func _goto_login() -> void:
|
||||
_state = LOGIN
|
||||
_reconnecting_game = false
|
||||
if _lifecycle:
|
||||
# GameScene 即将释放,不能让生命周期协调者保留悬空 Audio 引用。
|
||||
_lifecycle.bind(client)
|
||||
@@ -334,10 +371,7 @@ func _build_char_list() -> void:
|
||||
_ui.add_child(screen)
|
||||
screen.setup(client, _assets, _chars)
|
||||
screen.select_requested.connect(func(idx: int):
|
||||
if client.has_method("enter_game"):
|
||||
client.enter_game(idx)
|
||||
elif client.has_method("select_character"):
|
||||
client.select_character(idx))
|
||||
_enter_character(idx))
|
||||
screen.back_requested.connect(func():
|
||||
if client.has_method("disconnect_from_server"):
|
||||
client.disconnect_from_server()
|
||||
@@ -376,3 +410,10 @@ func _on_marks_ready_for_select() -> void:
|
||||
var sc: Node = _ui.get_node_or_null("CharSelect") if _ui else null
|
||||
if sc and sc.has_method("refresh_crest"):
|
||||
sc.refresh_crest()
|
||||
|
||||
func _enter_character(idx: int) -> void:
|
||||
_selected_char_slot = idx
|
||||
if client.has_method("enter_game"):
|
||||
client.enter_game(idx)
|
||||
elif client.has_method("select_character"):
|
||||
client.select_character(idx)
|
||||
|
||||
Reference in New Issue
Block a user