decdb74ade
Bump export_presets.cfg version to 2.3.5. Update CHANGELOG_DRAFT.md. Refactor lobby.gd into LobbyChat, LobbyMainMenu, LobbyRoomList, LobbyRoom. Move Nakama config to environment variables in nakama_manager.gd. Derive auth_manager.gd encryption key from OS.get_unique_id().sha256_text(). Remove Steam email auth fallback. Require auth ticket. Make GachaManager.pull() async in gacha_panel.gd. Remove dummy wallet seeding. Add store_type to IAP payload. Validate IAP receipts server-side in economy.lua. Register gacha module in main.lua. Clean backend_service.gd stubs. Fix featured_banners type safety in gacha_manager.gd. Guards non-array responses. Move tiles_armagedon_a1.res to assets/models/meshes/. Fix import fallback_path.
539 lines
20 KiB
GDScript
539 lines
20 KiB
GDScript
extends Control
|
|
|
|
# UI References - Main Menu
|
|
@onready var main_menu_panel = $MainMenuPanel
|
|
@onready var main_title = %Title
|
|
@onready var username_label = %Username
|
|
@onready var main_subtitle = %Subtitle
|
|
@onready var create_room_btn = %CreateRoomBtn
|
|
@onready var browse_rooms_btn = %BrowseRoomsBtn
|
|
@onready var tutorial_btn = %TutorialBtn
|
|
@onready var main_menu_profile_btn = %MainProfileBtn
|
|
@onready var avatar_display = %AvatarDisplay
|
|
@onready var lobby_settings_btn = %SettingsBtn
|
|
@onready var quit_btn = %QuitBtn
|
|
|
|
# Main Menu 3D Preview
|
|
@onready var character_root = %CharacterRoot
|
|
@onready var anim_player = %AnimationPlayer
|
|
|
|
# UI References - Currencies
|
|
@onready var gold_label = %GoldLabel
|
|
@onready var star_label = %StarLabel
|
|
|
|
# UI References - Server Selection
|
|
@onready var server_option = %ServerOption
|
|
@onready var server_ip_input = %ServerIPInput
|
|
|
|
# Leaderboard Reference
|
|
@onready var leaderboard_btn = %LeaderboardBtn
|
|
@onready var shop_btn = %CartBtn
|
|
@onready var top_right_profile_btn = %ProfileBtn
|
|
@onready var mailbox_btn = get_node_or_null("%MailboxBtn")
|
|
@onready var mail_badge = get_node_or_null("%MailBadge")
|
|
@onready var banner1_btn = get_node_or_null("%Banner1")
|
|
@onready var ticket_btn = get_node_or_null("%TicketBtn")
|
|
@onready var mailbox_panel = get_node_or_null("MailboxPanel")
|
|
|
|
# UI References - Room List
|
|
@onready var room_list_panel = %RoomListPanel
|
|
@onready var room_list = get_node_or_null("%RoomList")
|
|
@onready var match_id_input = get_node_or_null("%MatchIdInput")
|
|
@onready var refresh_btn = get_node_or_null("%RefreshBtn")
|
|
@onready var join_btn = get_node_or_null("%JoinBtn")
|
|
@onready var back_btn = get_node_or_null("%RoomListCloseBtn")
|
|
@onready var room_list_profile_btn = get_node_or_null("%RoomListProfileBtn")
|
|
@onready var item_template = get_node_or_null("%ItemTemplate")
|
|
|
|
@onready var room_player_username = get_node_or_null("%PlayerUsername")
|
|
@onready var room_player_score = get_node_or_null("%PlayerScore")
|
|
@onready var room_player_rank = get_node_or_null("%Rank")
|
|
@onready var room_avatar = get_node_or_null("%Avatar")
|
|
|
|
# Cached leaderboard rank for local player
|
|
var _local_player_rank: int = 0
|
|
|
|
# UI References - Lobby Panel
|
|
@onready var lobby_panel = $LobbyPanel
|
|
@onready var room_name_header = $LobbyPanel/RoomNameHeader
|
|
@onready var host_banner = $LobbyPanel/HostBanner
|
|
@onready var host_banner_label = $LobbyPanel/HostBanner/HostBannerLabel
|
|
|
|
|
|
# UI References - Top Bar
|
|
@onready var profile_btn = $LobbyPanel/TopBar/ProfileSection/ProfileBtn
|
|
@onready var logout_btn = $LobbyPanel/TopBar/ProfileSection/LogoutBtn
|
|
@onready var match_id_display = $LobbyPanel/TopBar/MatchIdContainer/MatchIdDisplay
|
|
@onready var copy_id_btn = $LobbyPanel/TopBar/MatchIdContainer/CopyIdBtn
|
|
@onready var duration_option = $LobbyPanel/TopBar/SettingsSection/DurationOption
|
|
@onready var duration_text_label = $LobbyPanel/TopBar/SettingsSection/DurationTextLabel
|
|
@onready var lobby_top_settings_btn = $LobbyPanel/TopBar/ProfileSection/LobbySettingsBtn
|
|
@onready var random_spawn_check = $LobbyPanel/TopBar/SettingsSection/RandomSpawnCheck
|
|
@onready var random_spawn_label = $LobbyPanel/TopBar/SettingsSection/RandomSpawnLabel
|
|
@onready var enable_timer_check = $LobbyPanel/TopBar/SettingsSection/EnableTimerCheck
|
|
@onready var enable_timer_label = $LobbyPanel/TopBar/SettingsSection/EnableTimerLabel
|
|
@onready var scarcity_option = $LobbyPanel/TopBar/SettingsSection/ScarcityOption
|
|
@onready var scarcity_label = $LobbyPanel/TopBar/SettingsSection/ScarcityLabel
|
|
@onready var scarcity_spacer = $LobbyPanel/TopBar/SettingsSection/ScarcitySpacer
|
|
@onready var spawn_spacer = $LobbyPanel/TopBar/SettingsSection/SpawnSpacer
|
|
@onready var timer_spacer = $LobbyPanel/TopBar/SettingsSection/TimerSpacer
|
|
@onready var game_mode_option = $LobbyPanel/TopBar/SettingsSection/GameModeOption
|
|
@onready var game_mode_text_label = $LobbyPanel/TopBar/SettingsSection/GameModeTextLabel
|
|
|
|
# Custom Settings Containers
|
|
var sng_settings_container: HBoxContainer
|
|
var sng_go_option: OptionButton
|
|
var sng_stop_option: OptionButton
|
|
var sng_goals_option: OptionButton
|
|
|
|
var doors_settings_container: HBoxContainer
|
|
var doors_swap_option: OptionButton
|
|
var doors_refresh_option: OptionButton
|
|
var doors_goals_option: OptionButton
|
|
|
|
# UI References - Player Slots
|
|
@onready var players_container = $LobbyPanel/PlayersContainer
|
|
@onready var players_container2 = $LobbyPanel/PlayersContainer2
|
|
@onready var player_slots: Array[Control] = []
|
|
|
|
# UI References - Area Selector
|
|
@onready var area_selector = $LobbyPanel/AreaSelector
|
|
@onready var area_left_btn = $LobbyPanel/AreaSelector/AreaLeftBtn
|
|
@onready var area_name_label = $LobbyPanel/AreaSelector/AreaName
|
|
@onready var area_right_btn = $LobbyPanel/AreaSelector/AreaRightBtn
|
|
|
|
# UI References - Bottom Bar
|
|
@onready var leave_btn = $LobbyPanel/BottomBar/LeaveBtn
|
|
@onready var ready_btn = $LobbyPanel/BottomBar/ReadyBtn
|
|
@onready var start_game_btn = $LobbyPanel/BottomBar/StartGameBtn
|
|
var invite_btn: Button
|
|
@onready var status_label = $LobbyPanel/StatusLabel
|
|
|
|
# Social Panel instance
|
|
var social_panel_instance: Control
|
|
|
|
# Lobby invite popup
|
|
var _invite_popup: AcceptDialog
|
|
var _pending_invite_match_id: String = ""
|
|
|
|
# UI References - Status
|
|
@onready var connection_status = $StatusBar/ConnectionStatus
|
|
|
|
# Character preview textures
|
|
var character_textures: Dictionary = {}
|
|
|
|
# Profile panel instance
|
|
var profile_panel_instance: Control
|
|
var admin_panel_instance: Control
|
|
|
|
# Store current match ID for copy function
|
|
var current_match_id: String = ""
|
|
|
|
var leaderboard_panel_instance: Control
|
|
var shop_panel_instance: Control
|
|
var daily_reward_panel_instance: Control
|
|
var _mailbox_panel_instance: Control
|
|
|
|
# Bot name tracking keyed by slot index to avoid re-generating on each update
|
|
var _bot_names: Dictionary = {}
|
|
|
|
# Room list filter ("" = all, "Freemode", "Stop n Go", etc.)
|
|
var _room_mode_filter: String = ""
|
|
|
|
# =============================================================================
|
|
# Chat System
|
|
# =============================================================================
|
|
var chat: LobbyChat
|
|
var main_menu: LobbyMainMenu
|
|
var room_list_helper: LobbyRoomList
|
|
var room_helper: LobbyRoom
|
|
|
|
@onready var chat_display: RichTextLabel = %RichTextLabel
|
|
@onready var chat_input: LineEdit = %ChatInput
|
|
@onready var chat_send_btn: Button = %SendBtn
|
|
|
|
var _friend_suggest_panel: PanelContainer
|
|
var _friend_suggest_list: ItemList
|
|
|
|
# Server Selection Controls (Now in tscn)
|
|
# var server_option: OptionButton
|
|
# var server_ip_input: LineEdit
|
|
|
|
|
|
func _ready():
|
|
chat = LobbyChat.new(self)
|
|
main_menu = LobbyMainMenu.new(self)
|
|
room_list_helper = LobbyRoomList.new(self)
|
|
room_helper = LobbyRoom.new(self)
|
|
|
|
# Start background music for Lobby
|
|
MusicManager.start_music()
|
|
|
|
# Load character textures
|
|
_load_character_textures()
|
|
|
|
# Server config UI is now in tscn
|
|
|
|
# Get player slot references
|
|
_setup_player_slots()
|
|
|
|
# Setup Game Mode specific UI dynamically
|
|
_create_custom_settings_ui()
|
|
|
|
# Initial UI update
|
|
_sync_room_profile_card()
|
|
|
|
# Connect Social / Friend UI
|
|
var global_chat_tab_btn = get_node_or_null("%GlobalChatTabBtn")
|
|
if global_chat_tab_btn:
|
|
global_chat_tab_btn.pressed.connect(func(): chat.switch_chat_tab("global"))
|
|
|
|
FriendManager.dm_message_received.connect(chat.on_lobby_dm_received)
|
|
|
|
|
|
|
|
|
|
# Connect Server Selection signals
|
|
if server_option:
|
|
server_option.item_selected.connect(_on_server_option_selected)
|
|
# Initialize state
|
|
_on_server_option_selected(server_option.selected)
|
|
if server_ip_input:
|
|
server_ip_input.text_submitted.connect(_on_server_ip_submitted)
|
|
server_ip_input.focus_exited.connect(func(): _on_server_ip_submitted(server_ip_input.text))
|
|
|
|
if match_id_input:
|
|
match_id_input.text_submitted.connect(func(_text): if room_list_helper: room_list_helper._on_join_pressed())
|
|
|
|
# Connect Side Tab switching
|
|
var play_side_btn = get_node_or_null("%PlayTabSideBtn")
|
|
var room_side_btn = get_node_or_null("%RoomTabSideBtn")
|
|
var room_tabs = get_node_or_null("%RoomListTabs")
|
|
if play_side_btn and room_side_btn and room_tabs:
|
|
play_side_btn.pressed.connect(func():
|
|
room_tabs.current_tab = 0
|
|
play_side_btn.button_pressed = true
|
|
room_side_btn.button_pressed = false
|
|
)
|
|
room_side_btn.pressed.connect(func():
|
|
room_tabs.current_tab = 1
|
|
play_side_btn.button_pressed = false
|
|
room_side_btn.button_pressed = true
|
|
)
|
|
|
|
# Connect Play Tab mode buttons
|
|
var room_free_mode_btn = get_node_or_null("%RoomFreeModeBtn")
|
|
var room_stop_n_go_btn = get_node_or_null("%RoomStopNGoBtn")
|
|
if room_free_mode_btn:
|
|
room_free_mode_btn.pressed.connect(func():
|
|
_room_mode_filter = "Freemode" if _room_mode_filter != "Freemode" else ""
|
|
LobbyManager.refresh_room_list()
|
|
)
|
|
if room_stop_n_go_btn:
|
|
room_stop_n_go_btn.pressed.connect(func():
|
|
_room_mode_filter = "Stop n Go" if _room_mode_filter != "Stop n Go" else ""
|
|
LobbyManager.refresh_room_list()
|
|
)
|
|
|
|
# Connect button signals - Lobby
|
|
if lobby_top_settings_btn:
|
|
lobby_top_settings_btn.pressed.connect(main_menu.on_settings_pressed)
|
|
|
|
# Connect Social / Friend UI
|
|
invite_btn = get_node_or_null("LobbyPanel/BottomBar/InviteBtn")
|
|
if invite_btn:
|
|
invite_btn.pressed.connect(room_helper.on_invite_friends_pressed)
|
|
|
|
# Connect UserProfileManager signals
|
|
UserProfileManager.profile_loaded.connect(func(_p): _sync_room_profile_card())
|
|
UserProfileManager.profile_updated.connect(func(): _sync_room_profile_card())
|
|
|
|
# Connect Mailbox UI
|
|
if MailManager:
|
|
MailManager.unread_count_changed.connect(_on_mail_unread_count_changed)
|
|
|
|
# Show main menu initially
|
|
_show_panel("main_menu")
|
|
|
|
# Check for disconnection reason from manager
|
|
if not LobbyManager.disconnect_reason.is_empty():
|
|
connection_status.text = LobbyManager.disconnect_reason
|
|
LobbyManager.disconnect_reason = ""
|
|
|
|
# Try to join global chat if already connected
|
|
if NakamaManager.is_connected_to_nakama():
|
|
chat.join_global_chat()
|
|
|
|
|
|
# =============================================================================
|
|
# Setup
|
|
# =============================================================================
|
|
|
|
const CHAR_NODE_MAP: Dictionary = {
|
|
"Copper": "Oldpop",
|
|
"Dabro": "Masbro",
|
|
"Gatot": "Gatot",
|
|
"Pip": "Bob"
|
|
}
|
|
|
|
func _setup_3d_preview() -> void:
|
|
"""Swaps out the active character inside the 3D MainMenu SubViewport."""
|
|
if not character_root:
|
|
return
|
|
var target_character = UserProfileManager.profile.get("loadout_character", "Copper")
|
|
var node_name = CHAR_NODE_MAP.get(target_character, "Bob")
|
|
|
|
for child in character_root.get_children():
|
|
if child is Node3D:
|
|
child.visible = (child.name == node_name)
|
|
|
|
if anim_player:
|
|
var new_root: Node3D = character_root.get_node_or_null(node_name) as Node3D
|
|
if new_root:
|
|
anim_player.root_node = new_root.get_path()
|
|
if anim_player.has_animation("animation-pack/idle"):
|
|
anim_player.play("animation-pack/idle")
|
|
elif anim_player.get_animation_list().size() > 0:
|
|
anim_player.play(anim_player.get_animation_list()[0])
|
|
|
|
# Apply equipped cosmetics so the lobby preview shows the current loadout
|
|
SkinManager.apply_loadout(character_root, UserProfileManager.loadout)
|
|
|
|
func _load_character_textures() -> void:
|
|
"""Load character preview textures."""
|
|
var characters = {
|
|
"Copper": "res://assets/graphics/character_selection/sc_characters/sc_copper.png",
|
|
"Dabro": "res://assets/graphics/character_selection/sc_characters/sc_dabro.png",
|
|
"Gatot": "res://assets/graphics/character_selection/sc_characters/sc_gatot.png",
|
|
"Pip": "res://assets/graphics/character_selection/sc_characters/sc_pip.png",
|
|
"Random": "res://assets/graphics/character_selection/sc_characters/sc_unknown.png"
|
|
}
|
|
for char_name in characters:
|
|
var tex_path = characters[char_name]
|
|
if ResourceLoader.exists(tex_path):
|
|
character_textures[char_name] = load(tex_path)
|
|
else:
|
|
print("[Lobby] Character texture not found: ", tex_path)
|
|
|
|
func _on_server_option_selected(index: int) -> void:
|
|
if main_subtitle and server_option:
|
|
main_subtitle.text = server_option.get_item_text(index).to_upper()
|
|
|
|
if index == 0:
|
|
# Nakama Localhost
|
|
if server_ip_input: server_ip_input.visible = false
|
|
NakamaManager.set_server("localhost")
|
|
LobbyManager.is_lan_mode = false
|
|
connection_status.text = "Mode: Local Testing (Nakama)"
|
|
elif index == 1:
|
|
# Nakama Remote
|
|
if server_ip_input:
|
|
server_ip_input.visible = true
|
|
server_ip_input.placeholder_text = "IP (100.x) or Tailscale Funnel URL..."
|
|
if server_ip_input: NakamaManager.set_server(server_ip_input.text)
|
|
LobbyManager.is_lan_mode = false
|
|
connection_status.text = "Mode: Online (Nakama Remote)"
|
|
elif index == 2:
|
|
# LAN Direct
|
|
if server_ip_input: server_ip_input.visible = false
|
|
LobbyManager.is_lan_mode = true
|
|
connection_status.text = "Mode: LAN Direct (No Server)"
|
|
elif index == 3:
|
|
# Tekton Dash EU
|
|
if server_ip_input: server_ip_input.visible = false
|
|
NakamaManager.set_server("tektondash.vps.webdock.cloud")
|
|
LobbyManager.is_lan_mode = false
|
|
connection_status.text = "Mode: Online (Tekton Dash EU)"
|
|
|
|
func _on_server_ip_submitted(new_text: String) -> void:
|
|
if server_option and server_option.selected == 1:
|
|
var host = new_text.strip_edges()
|
|
NakamaManager.set_server(host)
|
|
if host.ends_with(".ts.net"):
|
|
connection_status.text = "Using Tailscale Funnel: " + host
|
|
else:
|
|
connection_status.text = "Server IP updated: " + host
|
|
|
|
func _setup_game_modes() -> void:
|
|
if not game_mode_option: return
|
|
game_mode_option.clear()
|
|
for mode in LobbyManager.available_game_modes:
|
|
game_mode_option.add_item(mode)
|
|
|
|
# Select current mode
|
|
for i in range(game_mode_option.item_count):
|
|
if game_mode_option.get_item_text(i) == LobbyManager.game_mode:
|
|
game_mode_option.selected = i
|
|
break
|
|
|
|
func _setup_player_slots() -> void:
|
|
"""Get references to all player slot nodes."""
|
|
player_slots.clear()
|
|
|
|
# Slots 1-4 in Container 1
|
|
for i in range(1, 5):
|
|
var slot = players_container.get_node_or_null("PlayerSlot%d" % i)
|
|
if slot:
|
|
player_slots.append(slot)
|
|
_connect_slot_signals(slot, i)
|
|
|
|
# Slots 5-8 in Container 2
|
|
if players_container2:
|
|
for i in range(5, 9):
|
|
var slot = players_container2.get_node_or_null("PlayerSlot%d" % i)
|
|
if slot:
|
|
player_slots.append(slot)
|
|
_connect_slot_signals(slot, i)
|
|
|
|
func _connect_slot_signals(slot: Control, i: int):
|
|
# Connect character navigation buttons for all slots
|
|
var left_btn = slot.get_node_or_null("CharacterNav%d/CharLeftBtn%d" % [i, i])
|
|
var right_btn = slot.get_node_or_null("CharacterNav%d/CharRightBtn%d" % [i, i])
|
|
if left_btn:
|
|
left_btn.pressed.connect(func(): LobbyManager.cycle_character(-1))
|
|
if right_btn:
|
|
right_btn.pressed.connect(func(): LobbyManager.cycle_character(1))
|
|
|
|
# =============================================================================
|
|
# Panel Management
|
|
# =============================================================================
|
|
|
|
func _show_panel(panel_name: String) -> void:
|
|
main_menu_panel.visible = panel_name == "main_menu"
|
|
room_list_panel.visible = panel_name == "room_list"
|
|
lobby_panel.visible = panel_name == "lobby"
|
|
|
|
|
|
|
|
|
|
func _update_settings_visibility() -> void:
|
|
var is_host = LobbyManager.is_host
|
|
var is_freemode = LobbyManager.game_mode == "Freemode"
|
|
|
|
# Duration
|
|
var show_duration = is_freemode
|
|
duration_option.visible = is_host and show_duration
|
|
duration_text_label.visible = not is_host and show_duration
|
|
$LobbyPanel/TopBar/SettingsSection/DurationLabel.visible = show_duration
|
|
|
|
# Random Spawn
|
|
var show_spawn = is_freemode
|
|
random_spawn_check.visible = is_host and show_spawn
|
|
random_spawn_label.visible = not is_host and show_spawn
|
|
if spawn_spacer: spawn_spacer.visible = show_spawn
|
|
|
|
# Timer
|
|
var show_timer = is_freemode
|
|
enable_timer_check.visible = is_host and show_timer
|
|
enable_timer_label.visible = not is_host and show_timer
|
|
if timer_spacer: timer_spacer.visible = show_timer
|
|
|
|
# Scarcity
|
|
var show_scarcity = is_freemode
|
|
if scarcity_option: scarcity_option.visible = is_host and show_scarcity
|
|
if scarcity_label: scarcity_label.visible = not is_host and show_scarcity
|
|
if scarcity_spacer: scarcity_spacer.visible = show_scarcity
|
|
|
|
# Custom mode sets
|
|
var is_sng = LobbyManager.game_mode == "Stop n Go"
|
|
if sng_settings_container:
|
|
sng_settings_container.visible = is_sng
|
|
sng_go_option.disabled = not is_host
|
|
sng_stop_option.disabled = not is_host
|
|
sng_goals_option.disabled = not is_host
|
|
|
|
sng_goals_option.disabled = not is_host
|
|
|
|
func _create_custom_settings_ui() -> void:
|
|
var settings_section = $LobbyPanel/TopBar/SettingsSection
|
|
if not settings_section: return
|
|
|
|
# Stop n Go
|
|
sng_settings_container = HBoxContainer.new()
|
|
sng_settings_container.visible = false
|
|
settings_section.add_child(sng_settings_container)
|
|
|
|
_add_label(sng_settings_container, "Go Time:")
|
|
sng_go_option = OptionButton.new()
|
|
sng_go_option.add_item("10s"); sng_go_option.add_item("15s"); sng_go_option.add_item("25s")
|
|
sng_go_option.item_selected.connect(func(idx): if LobbyManager.is_host: LobbyManager.set_sng_go_duration([10, 15, 25][idx]))
|
|
sng_settings_container.add_child(sng_go_option)
|
|
|
|
_add_label(sng_settings_container, "Stop Time:")
|
|
sng_stop_option = OptionButton.new()
|
|
sng_stop_option.add_item("3s"); sng_stop_option.add_item("4s"); sng_stop_option.add_item("5s")
|
|
sng_stop_option.item_selected.connect(func(idx): if LobbyManager.is_host: LobbyManager.set_sng_stop_duration([3, 4, 5][idx]))
|
|
sng_settings_container.add_child(sng_stop_option)
|
|
|
|
_add_label(sng_settings_container, "Req Goals:")
|
|
sng_goals_option = OptionButton.new()
|
|
sng_goals_option.add_item("5"); sng_goals_option.add_item("8"); sng_goals_option.add_item("12")
|
|
sng_goals_option.item_selected.connect(func(idx): if LobbyManager.is_host: LobbyManager.set_sng_required_goals([5, 8, 12][idx]))
|
|
sng_settings_container.add_child(sng_goals_option)
|
|
|
|
# Move Game Mode selector to the far right
|
|
var gm_spacer = settings_section.get_node_or_null("GameModeSpacer")
|
|
var gm_option = settings_section.get_node_or_null("GameModeOption")
|
|
var gm_label = settings_section.get_node_or_null("GameModeTextLabel")
|
|
|
|
if gm_spacer: settings_section.move_child(gm_spacer, -1)
|
|
if gm_option: settings_section.move_child(gm_option, -1)
|
|
if gm_label: settings_section.move_child(gm_label, -1)
|
|
|
|
func _add_label(parent: Control, text: String):
|
|
var spacer = Control.new()
|
|
spacer.custom_minimum_size = Vector2(10, 0)
|
|
parent.add_child(spacer)
|
|
var lbl = Label.new()
|
|
lbl.text = text
|
|
parent.add_child(lbl)
|
|
|
|
func _on_mail_unread_count_changed(count: int) -> void:
|
|
if mail_badge:
|
|
if count > 0:
|
|
mail_badge.text = str(count) if count < 100 else "99+"
|
|
mail_badge.visible = true
|
|
else:
|
|
mail_badge.visible = false
|
|
|
|
func _sync_room_profile_card() -> void:
|
|
if room_player_username:
|
|
room_player_username.text = UserProfileManager.get_display_name()
|
|
if room_player_score:
|
|
room_player_score.text = "Score: %d" % UserProfileManager.get_stats().get("high_score", 0)
|
|
if room_player_rank:
|
|
room_player_rank.text = "Rank: %s" % (_local_player_rank if _local_player_rank > 0 else "-")
|
|
|
|
var avatar_path = UserProfileManager.get_avatar_url()
|
|
if not avatar_path.is_empty() and ResourceLoader.exists(avatar_path):
|
|
var tex = load(avatar_path)
|
|
if tex:
|
|
if avatar_display: avatar_display.texture = tex
|
|
if room_avatar:
|
|
if room_avatar is TextureRect:
|
|
room_avatar.texture = tex
|
|
elif room_avatar is Panel:
|
|
var style = StyleBoxTexture.new()
|
|
style.texture = tex
|
|
room_avatar.add_theme_stylebox_override("panel", style)
|
|
|
|
if main_menu_profile_btn:
|
|
var tr = main_menu_profile_btn.get_node_or_null("TextureRect")
|
|
if tr: tr.texture = tex
|
|
if top_right_profile_btn:
|
|
var tr = top_right_profile_btn.get_node_or_null("TextureRect")
|
|
if tr: tr.texture = tex
|
|
if room_list_profile_btn:
|
|
var tr = room_list_profile_btn.get_node_or_null("TextureRect")
|
|
if tr: tr.texture = tex
|
|
|
|
func _apply_loadout_character() -> void:
|
|
"""Apply the player's saved loadout default character to LobbyManager before entering a room."""
|
|
var saved_char: String = UserProfileManager.profile.get("loadout_character", "")
|
|
if saved_char.is_empty():
|
|
return
|
|
var idx := LobbyManager.available_characters.find(saved_char)
|
|
if idx != -1:
|
|
LobbyManager.local_character_index = idx
|
|
print("[Lobby] Loadout character applied: ", saved_char)
|