Files
mtgodot-poc/project/login.gd
T
2026-09-02 07:03:25 +08:00

157 lines
4.9 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.
# 登录界面 —— 服务器/账号/密码输入 + 连接,接 M2Client。
# 成功(char_list)后打印槽位;实际项目里在此切到 charselect.gd。
# 用法:godot --path project --script login.gd --auto 用默认值直接连)
extends SceneTree
const UiKit = preload("res://ui_kit.gd")
const Audio = preload("res://audio.gd")
const Locale = preload("res://locale.gd")
const AppLifecycle = preload("res://app_lifecycle.gd")
const GameScene = preload("res://game_scene.gd")
var _assets: String
var _client: Node
var _audio: Node
var _life: Node
var _layer: CanvasLayer
var _game: Node3D
var _auto_select := false
var _loc: RefCounted
var _host: LineEdit
var _id: LineEdit
var _pw: LineEdit
var _status: Label
var _t := 0.0
func _init() -> void:
_assets = AssetRoot.path()
_loc = Locale.new()
_loc.setup(_assets, "en")
_audio = Audio.new()
get_root().add_child(_audio)
_audio.setup(_assets)
# F5:登录界面没有游戏逻辑要暂停,但后台时仍停 BGM / 挂起连接
_life = AppLifecycle.new()
_life.pause_tree_on_background = false
get_root().add_child(_life)
_life.bind(null, _audio)
_layer = CanvasLayer.new()
var layer := _layer
get_root().add_child(layer)
var bg := ColorRect.new()
bg.color = Color(0.08, 0.09, 0.12)
bg.set_anchors_preset(Control.PRESET_FULL_RECT)
layer.add_child(bg)
var panel := UiKit.board(_assets, "board", 32, 128)
panel.set_anchors_preset(Control.PRESET_CENTER)
panel.position = Vector2(-220, -150)
panel.size = Vector2(440, 300)
layer.add_child(panel)
var v := VBoxContainer.new()
v.position = Vector2(40, 36)
v.custom_minimum_size = Vector2(360, 0)
v.add_theme_constant_override("separation", 12)
panel.add_child(v)
var title := Label.new()
title.text = " " + _loc.t("LOGIN_CONNECT")
title.add_theme_font_size_override("font_size", 20)
v.add_child(title)
_host = _field(v, _loc.t("LOGIN_DEFAULT_SERVERADDR").split(",")[0], "192.168.21.203")
_id = _field(v, _loc.t("LOGIN_ID"), "admin")
_pw = _field(v, _loc.t("LOGIN_PASSWORD"), "123456789")
_pw.secret = true
var btn := Button.new()
btn.text = _loc.t("LOGIN_CONNECT")
btn.custom_minimum_size = Vector2(0, 40)
btn.pressed.connect(_connect)
v.add_child(btn)
_status = Label.new()
_status.text = _loc.t("LOGIN_CONNECTING")
v.add_child(_status)
if "--auto" in OS.get_cmdline_user_args() or "--auto" in OS.get_cmdline_args():
_connect()
func _field(parent: Control, label: String, val: String) -> LineEdit:
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 10)
var l := Label.new()
l.text = label
l.custom_minimum_size = Vector2(64, 0)
row.add_child(l)
var le := LineEdit.new()
le.text = val
le.custom_minimum_size = Vector2(260, 0)
row.add_child(le)
parent.add_child(row)
return le
func _connect() -> void:
if not ClassDB.class_exists("M2Client"):
_status.text = "M2Client 未注册(扩展没编?)"
return
if _client:
_client.call("disconnect_from_server")
_client.queue_free()
_client = ClassDB.instantiate("M2Client")
get_root().add_child(_client)
_client.connect("stage_changed", func(s): _msg("阶段: " + s))
_client.connect("auth_ok", func(k):
_msg("认证成功 login_key=0x%08X" % k)
_audio.play_ui("loginok"))
_client.connect("login_failed", func(r):
_msg("失败: " + r)
_audio.play_ui("loginfail"))
_client.connect("phase_changed", func(p): _msg("游戏相位: " + p))
_client.connect("char_list", _on_chars)
_client.connect("entered_game", _on_entered_game)
_client.connect("disconnected", func(r): _msg("断开: " + r))
_client.connect("resumed", func():
# 回前台:若后台期间 OS 掐了 TCP,下一次 pump 会发 disconnected
# 曾在游戏里就自动重连。
if _client.call("is_in_game"):
_msg("回前台,尝试重连…")
_client.call("reconnect"))
_life.bind(_client, _audio)
var h := _host.text
_client.call("connect_to_server", h, 11000, h, 13002, _id.text, _pw.text)
_msg("连接 %s ..." % h)
func _on_chars(list: Array) -> void:
_msg("角色列表: %d 个" % list.size())
for d in list:
print("[login] slot %d: %s (job %d, Lv.%d) @ (%d,%d)" % [
d.get("index", -1), d.get("name", "?"), d.get("job", 0),
d.get("level", 0), d.get("x", 0), d.get("y", 0)])
# 简版:自动选第一个非空槽进游戏。正式版切到 charselect.gd。
if list.size() > 0 and (_auto_select or "--auto" in OS.get_cmdline_args()):
var idx: int = int(list[0].get("index", 0))
_msg("自动选择槽位 %d ..." % idx)
_client.call("select_character", idx)
func _on_entered_game() -> void:
_msg("已进入游戏 —— 加载场景")
if _layer:
_layer.visible = false
if _life: # 让 game_scene 自己的 AppLifecycle 接管
_life.queue_free()
_life = null
_game = GameScene.new()
get_root().add_child(_game)
_game.setup(_client, _assets)
func _msg(t: String) -> void:
if _status:
_status.text = t
print("[login] ", t)
func _process(_dt: float) -> bool:
return false