feat: 2.3.2
This commit is contained in:
@@ -10,17 +10,19 @@ signal closed
|
||||
# -------------------------------------------------------------------------
|
||||
@onready var back_btn := %BackBtn as Button
|
||||
@onready var refresh_btn := %RefreshBtn as Button
|
||||
@onready var sync_btn := %SyncBtn as Button
|
||||
@onready var sort_score_btn := %SortScoreBtn as Button
|
||||
@onready var sort_win_rate_btn := %SortWinRateBtn as Button
|
||||
@onready var sort_games_btn := %SortGamesBtn as Button
|
||||
@onready var leaderboard_list := %LeaderboardList as VBoxContainer
|
||||
@onready var status_label := %StatusLabel as Label
|
||||
@onready var item_template := %ItemTemplate as PanelContainer
|
||||
|
||||
# 3D Preview
|
||||
@onready var character_root := %CharacterRoot as Node3D
|
||||
@onready var selected_name_label := %SelectedNameLabel as Label
|
||||
@onready var selected_rank_label := %SelectedRankLabel as Label
|
||||
@onready var selected_score_label := %SelectedScoreLabel as Label
|
||||
@onready var selected_avatar_rect := %SelectedAvatarRect as TextureRect
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# State
|
||||
@@ -43,13 +45,15 @@ const AVATAR_TO_CHAR: Array[String] = ["Pip", "Gatot", "Dabro", "Copper"]
|
||||
func _ready() -> void:
|
||||
back_btn.pressed.connect(_on_close_pressed)
|
||||
refresh_btn.pressed.connect(_fetch_leaderboard_data)
|
||||
sync_btn.pressed.connect(_on_sync_pressed)
|
||||
|
||||
sort_score_btn.pressed.connect(func(): _sort_by("high_score"))
|
||||
sort_win_rate_btn.pressed.connect(func(): _sort_by("win_rate"))
|
||||
sort_games_btn.pressed.connect(func(): _sort_by("games_played"))
|
||||
_update_tab_visuals()
|
||||
_setup_3d_preview()
|
||||
|
||||
if item_template:
|
||||
item_template.hide()
|
||||
|
||||
# Listen to profile and stats changes to keep the panel updated
|
||||
UserProfileManager.profile_updated.connect(_on_profile_or_stats_changed)
|
||||
@@ -79,17 +83,6 @@ func _on_close_pressed() -> void:
|
||||
hide()
|
||||
emit_signal("closed")
|
||||
|
||||
func _on_sync_pressed() -> void:
|
||||
"""Push the current player's stored stats up to the native Nakama leaderboard."""
|
||||
if not NakamaManager.session or AuthManager.is_guest:
|
||||
status_label.text = "Must be logged in to sync"
|
||||
return
|
||||
status_label.text = "Syncing your score..."
|
||||
await UserProfileManager.submit_to_leaderboard()
|
||||
status_label.text = "Synced! Refreshing..."
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
_fetch_leaderboard_data()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Data
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -99,8 +92,10 @@ func _fetch_leaderboard_data() -> void:
|
||||
return
|
||||
|
||||
status_label.text = "Fetching Leaderboard..."
|
||||
status_label.show()
|
||||
for child in leaderboard_list.get_children():
|
||||
child.queue_free()
|
||||
if child != item_template:
|
||||
child.queue_free()
|
||||
|
||||
# Try native Nakama leaderboard first (fastest, ranked already)
|
||||
var native_data = await _fetch_native_leaderboard()
|
||||
@@ -231,90 +226,76 @@ func _update_tab_visuals() -> void:
|
||||
|
||||
func _populate_list() -> void:
|
||||
for child in leaderboard_list.get_children():
|
||||
child.queue_free()
|
||||
if child != item_template:
|
||||
child.queue_free()
|
||||
|
||||
if leaderboard_data.size() == 0:
|
||||
status_label.text = "No players found.\nPlay a match to appear here!"
|
||||
status_label.show()
|
||||
return
|
||||
|
||||
status_label.hide()
|
||||
for i in range(leaderboard_data.size()):
|
||||
var entry = leaderboard_data[i]
|
||||
_create_leaderboard_item(i + 1, entry, i)
|
||||
|
||||
func _create_leaderboard_item(rank: int, entry: Dictionary, index: int) -> void:
|
||||
var item = PanelContainer.new()
|
||||
var style = StyleBoxFlat.new()
|
||||
var item = item_template.duplicate()
|
||||
item.show()
|
||||
|
||||
var style: StyleBoxFlat
|
||||
if item.has_theme_stylebox_override("panel"):
|
||||
style = item.get_theme_stylebox("panel").duplicate()
|
||||
else:
|
||||
style = StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.25, 0.3, 0.35, 1.0)
|
||||
style.set_corner_radius_all(8)
|
||||
|
||||
if index == current_selected_index:
|
||||
# Highlight color for the currently selected player row
|
||||
style.bg_color = Color(0.25, 0.35, 0.20, 1.0)
|
||||
elif rank <= 3:
|
||||
style.bg_color = Color(0.2, 0.2, 0.15, 1.0)
|
||||
style.bg_color = Color(0.35, 0.45, 0.30, 1.0)
|
||||
else:
|
||||
style.bg_color = Color(0.15, 0.15, 0.15, 1.0)
|
||||
style.bg_color = Color(0.25, 0.3, 0.35, 1.0)
|
||||
|
||||
style.set_corner_radius_all(4)
|
||||
style.content_margin_left = 10
|
||||
style.content_margin_right = 10
|
||||
style.content_margin_top = 8
|
||||
style.content_margin_bottom = 8
|
||||
item.add_theme_stylebox_override("panel", style)
|
||||
|
||||
var hbox = HBoxContainer.new()
|
||||
hbox.add_theme_constant_override("separation", 16)
|
||||
item.add_child(hbox)
|
||||
var rank_label = item.get_node("HBoxContainer/RankLabel") as Label
|
||||
if rank_label:
|
||||
var rank_suffix = "th"
|
||||
if rank % 10 == 1 and rank % 100 != 11: rank_suffix = "st"
|
||||
elif rank % 10 == 2 and rank % 100 != 12: rank_suffix = "nd"
|
||||
elif rank % 10 == 3 and rank % 100 != 13: rank_suffix = "rd"
|
||||
rank_label.text = str(rank) + rank_suffix
|
||||
|
||||
# Rank
|
||||
var rank_label = Label.new()
|
||||
rank_label.text = "#" + str(rank)
|
||||
rank_label.custom_minimum_size = Vector2(40, 0)
|
||||
match rank:
|
||||
1: rank_label.add_theme_color_override("font_color", Color.GOLD)
|
||||
2: rank_label.add_theme_color_override("font_color", Color.SILVER)
|
||||
3: rank_label.add_theme_color_override("font_color", Color.DARK_ORANGE)
|
||||
_: rank_label.add_theme_color_override("font_color", Color.LIGHT_GRAY)
|
||||
hbox.add_child(rank_label)
|
||||
match rank:
|
||||
1: rank_label.add_theme_color_override("font_color", Color.GOLD)
|
||||
2: rank_label.add_theme_color_override("font_color", Color.SILVER)
|
||||
3: rank_label.add_theme_color_override("font_color", Color.DARK_ORANGE)
|
||||
_: rank_label.add_theme_color_override("font_color", Color.WHITE)
|
||||
|
||||
# Avatar
|
||||
var avatar_rect = TextureRect.new()
|
||||
avatar_rect.custom_minimum_size = Vector2(32, 32)
|
||||
avatar_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
|
||||
var avatar_url = entry.get("avatar_url", "")
|
||||
if avatar_url.is_empty() or not ResourceLoader.exists(avatar_url):
|
||||
if not avatar_url.is_empty():
|
||||
print("[Leaderboard] Avatar URL not found or invalid: ", avatar_url)
|
||||
avatar_url = UserProfileManager.AVATARS[0]
|
||||
|
||||
avatar_rect.texture = load(avatar_url)
|
||||
hbox.add_child(avatar_rect)
|
||||
var avatar_rect = item.get_node("HBoxContainer/Margin/InnerHBox/AvatarRect") as TextureRect
|
||||
if avatar_rect:
|
||||
var avatar_url = entry.get("avatar_url", "")
|
||||
if avatar_url.is_empty() or not ResourceLoader.exists(avatar_url):
|
||||
avatar_url = UserProfileManager.AVATARS[0]
|
||||
avatar_rect.texture = load(avatar_url)
|
||||
|
||||
# Name
|
||||
var name_label = Label.new()
|
||||
name_label.text = entry.get("display_name", "Unknown")
|
||||
name_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
name_label.add_theme_color_override("font_color", Color.WHITE)
|
||||
hbox.add_child(name_label)
|
||||
var name_label = item.get_node("HBoxContainer/Margin/InnerHBox/NameLabel") as Label
|
||||
if name_label:
|
||||
name_label.text = entry.get("display_name", "Unknown")
|
||||
|
||||
# Value
|
||||
var value_label = Label.new()
|
||||
var color = Color(0.647, 0.996, 0.224, 1)
|
||||
match current_sort_key:
|
||||
"high_score": value_label.text = str(entry.get("high_score", 0))
|
||||
"win_rate": value_label.text = "%.1f%%" % entry.get("win_rate", 0.0)
|
||||
"games_played": value_label.text = str(entry.get("games_played", 0))
|
||||
value_label.add_theme_color_override("font_color", color)
|
||||
value_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
value_label.custom_minimum_size = Vector2(80, 0)
|
||||
hbox.add_child(value_label)
|
||||
var value_label = item.get_node("HBoxContainer/ValueLabel") as Label
|
||||
if value_label:
|
||||
match current_sort_key:
|
||||
"high_score": value_label.text = str(entry.get("high_score", 0))
|
||||
"win_rate": value_label.text = "%.1f%%" % entry.get("win_rate", 0.0)
|
||||
"games_played": value_label.text = str(entry.get("games_played", 0))
|
||||
|
||||
leaderboard_list.add_child(item)
|
||||
|
||||
# Make row clickable to update 3D preview
|
||||
item.gui_input.connect(func(event: InputEvent):
|
||||
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
|
||||
current_selected_index = index
|
||||
_populate_list() # Re-draw list to apply the new active highlight colors visually
|
||||
_populate_list()
|
||||
_show_entry_preview(index)
|
||||
)
|
||||
item.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
@@ -347,8 +328,18 @@ func _show_entry_preview(index: int) -> void:
|
||||
|
||||
var display_name: String = entry.get("display_name", "Unknown")
|
||||
var rank := index + 1
|
||||
selected_name_label.text = display_name
|
||||
selected_rank_label.text = "#%d" % rank
|
||||
if selected_name_label: selected_name_label.text = display_name
|
||||
if selected_rank_label: selected_rank_label.text = "Rank #%d" % rank
|
||||
if selected_score_label:
|
||||
match current_sort_key:
|
||||
"high_score": selected_score_label.text = str(entry.get("high_score", 0))
|
||||
"win_rate": selected_score_label.text = "%.1f%%" % entry.get("win_rate", 0.0)
|
||||
"games_played": selected_score_label.text = str(entry.get("games_played", 0))
|
||||
if selected_avatar_rect:
|
||||
var avatar_url2 = entry.get("avatar_url", "")
|
||||
if avatar_url2.is_empty() or not ResourceLoader.exists(avatar_url2):
|
||||
avatar_url2 = UserProfileManager.AVATARS[0]
|
||||
selected_avatar_rect.texture = load(avatar_url2)
|
||||
|
||||
func _update_3d_preview(character_name: String) -> void:
|
||||
if not character_root:
|
||||
|
||||
Reference in New Issue
Block a user