feat: add battlepass slider and quest list tabs to lobby HUD
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
extends Panel
|
||||
|
||||
@onready var _slider = $Content/ScrollContainer
|
||||
@onready var _ticket = $Ticket
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if _slider.has_signal("page_changed"):
|
||||
_slider.page_changed.connect(_on_page_changed)
|
||||
|
||||
|
||||
func _on_page_changed(index: int) -> void:
|
||||
_ticket.show_index(index)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dc5dh15rrdc4
|
||||
@@ -0,0 +1,53 @@
|
||||
extends Panel
|
||||
|
||||
const DIP_DURATION := 0.36
|
||||
|
||||
@onready var _tickets: Array = get_children().filter(func(c): return c is TextureRect)
|
||||
|
||||
var _current_index := 0
|
||||
var _tween: Tween
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for i in _tickets.size():
|
||||
_tickets[i].visible = (i == 0)
|
||||
_tickets[i].modulate.a = 1.0
|
||||
|
||||
|
||||
func show_index(index: int, animate: bool = true) -> void:
|
||||
if index < 0 or index >= _tickets.size() or index == _current_index:
|
||||
return
|
||||
|
||||
var from_ticket: TextureRect = _tickets[_current_index]
|
||||
var to_ticket: TextureRect = _tickets[index]
|
||||
|
||||
if not animate:
|
||||
from_ticket.visible = false
|
||||
to_ticket.visible = true
|
||||
to_ticket.modulate.a = 1.0
|
||||
_current_index = index
|
||||
return
|
||||
|
||||
if _tween:
|
||||
_tween.kill()
|
||||
|
||||
var from_mat: ShaderMaterial = from_ticket.material
|
||||
var to_mat: ShaderMaterial = to_ticket.material
|
||||
|
||||
_tween = create_tween()
|
||||
_tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
||||
if from_mat:
|
||||
_tween.tween_method(func(v): from_mat.set_shader_parameter("blur_amount", v), 0.0, 1.0, DIP_DURATION * 0.5)
|
||||
_tween.parallel().tween_property(from_ticket, "modulate:a", 0.0, DIP_DURATION * 0.5)
|
||||
|
||||
_tween.tween_callback(func():
|
||||
from_ticket.visible = false
|
||||
to_ticket.modulate.a = 0.0
|
||||
to_ticket.visible = true
|
||||
_current_index = index
|
||||
)
|
||||
|
||||
_tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
|
||||
if to_mat:
|
||||
_tween.tween_method(func(v): to_mat.set_shader_parameter("blur_amount", v), 1.0, 0.0, DIP_DURATION * 0.5)
|
||||
_tween.parallel().tween_property(to_ticket, "modulate:a", 1.0, DIP_DURATION * 0.5)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bwu41vcu5t8nd
|
||||
+82
-34
@@ -10,6 +10,8 @@ var _active_chat_context: String = "global"
|
||||
var _dm_tabs: Dictionary = {}
|
||||
var _dm_messages: Dictionary = {}
|
||||
var _chat_config: Dictionary = {"prefix": "", "max_messages": 50, "max_age_days": 0}
|
||||
var _global_chat_loading: bool = false
|
||||
var _dm_loading: Dictionary = {}
|
||||
|
||||
func _init(p_lobby: Control):
|
||||
lobby = p_lobby
|
||||
@@ -19,26 +21,41 @@ func _init(p_lobby: Control):
|
||||
if lobby.chat_input:
|
||||
lobby.chat_input.text_submitted.connect(func(_t): _on_chat_send_pressed())
|
||||
lobby.chat_input.text_changed.connect(_on_chat_input_changed)
|
||||
|
||||
|
||||
var global_btn = lobby.get_node_or_null("%GlobalChatTabBtn")
|
||||
if global_btn:
|
||||
global_btn.pressed.connect(func(): switch_chat_tab("global"))
|
||||
|
||||
var server_btn = lobby.get_node_or_null("%ServerChatTabBtn")
|
||||
if server_btn:
|
||||
server_btn.pressed.connect(func(): switch_chat_tab("server"))
|
||||
|
||||
_setup_friend_suggest_ui()
|
||||
|
||||
func join_global_chat() -> void:
|
||||
if _chat_channel != null:
|
||||
if _chat_channel != null or _global_chat_loading:
|
||||
return
|
||||
|
||||
|
||||
_global_chat_loading = true
|
||||
_refresh_chat_display()
|
||||
|
||||
var socket = NakamaManager.socket
|
||||
if not socket or not socket.is_connected_to_host():
|
||||
push_warning("[Chat] Socket not connected, skipping chat join.")
|
||||
_global_chat_loading = false
|
||||
_refresh_chat_display()
|
||||
return
|
||||
|
||||
|
||||
var result = await socket.join_chat_async(GLOBAL_CHAT_ROOM,
|
||||
NakamaSocket.ChannelType.Room,
|
||||
true, false)
|
||||
|
||||
|
||||
if result.is_exception():
|
||||
push_warning("[Chat] Failed to join global chat: " + result.get_exception().message)
|
||||
_global_chat_loading = false
|
||||
_refresh_chat_display()
|
||||
return
|
||||
|
||||
|
||||
_chat_channel = result
|
||||
print("[Chat] Joined global channel: ", _chat_channel.id)
|
||||
|
||||
@@ -51,26 +68,28 @@ func join_global_chat() -> void:
|
||||
if cfg_res.has("config"):
|
||||
_chat_config = cfg_res["config"]
|
||||
|
||||
_chat_messages.clear()
|
||||
var limit: int = _chat_config.get("max_messages", 50)
|
||||
var history_entries: Array = []
|
||||
var history_result = await NakamaManager.client.list_channel_messages_async(NakamaManager.session, _chat_channel.id, limit, false)
|
||||
if not history_result.is_exception() and history_result.messages:
|
||||
var msgs = history_result.messages.duplicate()
|
||||
msgs.reverse()
|
||||
for msg in msgs:
|
||||
_add_chat_message(msg, false)
|
||||
history_entries.append(_parse_chat_message(msg))
|
||||
|
||||
# Inject admin system prefix if configured
|
||||
var prefix: String = _chat_config.get("prefix", "")
|
||||
if not prefix.is_empty():
|
||||
_chat_messages.insert(0, {
|
||||
history_entries.insert(0, {
|
||||
"sender": "SYSTEM",
|
||||
"content": prefix,
|
||||
"ts": _get_local_time(),
|
||||
"date": Time.get_date_string_from_system()
|
||||
})
|
||||
|
||||
|
||||
_chat_messages = history_entries + _chat_messages
|
||||
_trim_old_messages()
|
||||
_global_chat_loading = false
|
||||
_refresh_chat_display()
|
||||
|
||||
func _on_chat_message_received(message) -> void:
|
||||
@@ -80,29 +99,32 @@ func _on_chat_message_received(message) -> void:
|
||||
return
|
||||
_add_chat_message(message, true)
|
||||
|
||||
func _add_chat_message(message, refresh_display: bool) -> void:
|
||||
func _parse_chat_message(message) -> Dictionary:
|
||||
var text: String = ""
|
||||
var parsed = JSON.parse_string(message.content)
|
||||
if typeof(parsed) == TYPE_DICTIONARY:
|
||||
text = parsed.get("msg", message.content)
|
||||
else:
|
||||
text = message.content
|
||||
|
||||
|
||||
var sender: String = message.username
|
||||
if sender.is_empty() and message.sender_id:
|
||||
sender = message.sender_id.substr(0, 8)
|
||||
elif sender.is_empty():
|
||||
sender = "Unknown"
|
||||
|
||||
|
||||
var ts_str: String = _format_nakama_time(message.create_time)
|
||||
|
||||
_chat_messages.append({
|
||||
|
||||
return {
|
||||
"sender": sender,
|
||||
"content": text,
|
||||
"ts": ts_str,
|
||||
"date": message.create_time.substr(0, 10) if message.create_time else Time.get_date_string_from_system()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func _add_chat_message(message, refresh_display: bool) -> void:
|
||||
_chat_messages.append(_parse_chat_message(message))
|
||||
|
||||
if refresh_display:
|
||||
_trim_old_messages()
|
||||
_refresh_chat_display()
|
||||
@@ -209,16 +231,21 @@ func _open_dm_tab(user_id: String, username: String) -> void:
|
||||
if not _dm_tabs.has(user_id):
|
||||
_create_dm_tab(user_id, username)
|
||||
_dm_messages[user_id] = []
|
||||
_dm_loading[user_id] = true
|
||||
switch_chat_tab(user_id)
|
||||
|
||||
|
||||
var history = await FriendManager.get_dm_history(user_id)
|
||||
var my_id = NakamaManager.session.user_id if NakamaManager.session else ""
|
||||
var history_entries: Array = []
|
||||
for entry in history:
|
||||
var is_self = entry.get("from") == my_id
|
||||
var sender_name = "You" if is_self else username
|
||||
var ts = _format_nakama_time(entry.get("create_time", ""))
|
||||
_dm_messages[user_id].append({"sender": sender_name, "content": entry.get("msg", ""), "ts": ts})
|
||||
|
||||
history_entries.append({"sender": sender_name, "content": entry.get("msg", ""), "ts": ts})
|
||||
|
||||
_dm_messages[user_id] = history_entries + _dm_messages[user_id]
|
||||
_dm_loading[user_id] = false
|
||||
|
||||
if _active_chat_context == user_id:
|
||||
_refresh_chat_display()
|
||||
else:
|
||||
@@ -256,16 +283,34 @@ func _close_dm_tab(user_id: String) -> void:
|
||||
func switch_chat_tab(context_id: String) -> void:
|
||||
_active_chat_context = context_id
|
||||
_refresh_chat_display()
|
||||
|
||||
var tabs_container = lobby.get_node_or_null("%ChatTabsContainer")
|
||||
if tabs_container:
|
||||
var global_btn = lobby.get_node_or_null("%GlobalChatTabBtn")
|
||||
if global_btn:
|
||||
global_btn.modulate = Color(1.0, 1.0, 1.0) if context_id == "global" else Color(0.6, 0.6, 0.6)
|
||||
|
||||
for u_id in _dm_tabs:
|
||||
var tab_hbox = _dm_tabs[u_id]
|
||||
tab_hbox.modulate = Color(1.0, 1.0, 1.0) if context_id == u_id else Color(0.6, 0.6, 0.6)
|
||||
|
||||
var global_btn = lobby.get_node_or_null("%GlobalChatTabBtn")
|
||||
if global_btn:
|
||||
global_btn.button_pressed = (context_id == "global")
|
||||
|
||||
var server_btn = lobby.get_node_or_null("%ServerChatTabBtn")
|
||||
if server_btn:
|
||||
server_btn.button_pressed = (context_id == "server")
|
||||
|
||||
for u_id in _dm_tabs:
|
||||
var tab_hbox = _dm_tabs[u_id]
|
||||
var dm_btn = tab_hbox.get_node_or_null("DMTabBtn")
|
||||
if dm_btn:
|
||||
dm_btn.button_pressed = (context_id == u_id)
|
||||
|
||||
if lobby.chat_input:
|
||||
lobby.chat_input.placeholder_text = "Send to %s..." % _get_context_display_name(context_id)
|
||||
|
||||
func _get_context_display_name(context_id: String) -> String:
|
||||
if context_id == "global":
|
||||
return "World"
|
||||
if context_id == "server":
|
||||
return "Server"
|
||||
if _dm_tabs.has(context_id):
|
||||
var btn = _dm_tabs[context_id].get_node_or_null("DMTabBtn")
|
||||
if btn:
|
||||
return btn.text
|
||||
return "Chat"
|
||||
|
||||
func _setup_friend_suggest_ui() -> void:
|
||||
lobby._friend_suggest_panel = lobby.get_node_or_null("%FriendSuggestPanel")
|
||||
@@ -331,12 +376,15 @@ func _refresh_chat_display() -> void:
|
||||
messages_to_show = []
|
||||
|
||||
for msg in messages_to_show:
|
||||
var ts: String = msg.get("ts", "")
|
||||
var sender: String = msg.get("sender", "?")
|
||||
var text: String = msg.get("content", "")
|
||||
|
||||
lobby.chat_display.append_text("[color=#888888][%s][/color] [b]%s:[/b] %s\n" % [ts, sender, text])
|
||||
|
||||
|
||||
lobby.chat_display.append_text("[b]%s[/b]\n[color=#c7d3e0]%s[/color]\n\n" % [sender, text])
|
||||
|
||||
var is_loading: bool = _global_chat_loading if _active_chat_context == "global" else _dm_loading.get(_active_chat_context, false)
|
||||
if is_loading:
|
||||
lobby.chat_display.append_text("[i][color=#8a97a8]Loading messages...[/color][/i]\n")
|
||||
|
||||
if lobby.chat_display:
|
||||
var scrollbar = lobby.chat_display.get_v_scroll_bar()
|
||||
if scrollbar:
|
||||
|
||||
@@ -153,8 +153,7 @@ func _on_room_joined(room_data: Dictionary) -> void:
|
||||
_on_enable_cycle_timer_changed(LobbyManager.enable_cycle_timer)
|
||||
_on_scarcity_mode_changed(LobbyManager.scarcity_mode)
|
||||
_on_sng_update()
|
||||
_on_doors_update()
|
||||
|
||||
|
||||
if lobby.area_left_btn: lobby.area_left_btn.disabled = not is_host
|
||||
if lobby.area_right_btn: lobby.area_right_btn.disabled = not is_host
|
||||
if lobby.area_name_label: lobby.area_name_label.text = LobbyManager.get_selected_area()
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
extends Panel
|
||||
|
||||
signal period_changed(period: String)
|
||||
|
||||
@onready var _daily_btn: Button = %DailyTabBtn
|
||||
@onready var _weekly_btn: Button = %WeeklyTabBtn
|
||||
@onready var _monthly_btn: Button = %MonthlyTabBtn
|
||||
|
||||
var _active := "daily"
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_daily_btn.pressed.connect(_select.bind("daily"))
|
||||
_weekly_btn.pressed.connect(_select.bind("weekly"))
|
||||
_monthly_btn.pressed.connect(_select.bind("monthly"))
|
||||
|
||||
|
||||
func _select(period: String) -> void:
|
||||
if period == _active:
|
||||
return
|
||||
_active = period
|
||||
_daily_btn.button_pressed = (period == "daily")
|
||||
_weekly_btn.button_pressed = (period == "weekly")
|
||||
_monthly_btn.button_pressed = (period == "monthly")
|
||||
period_changed.emit(period)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cas5sc40ampq1
|
||||
Reference in New Issue
Block a user