feat: bug fix social system
This commit is contained in:
+46
-21
@@ -125,7 +125,7 @@ var _bot_names: Dictionary = {}
|
||||
# =============================================================================
|
||||
# Chat System
|
||||
# =============================================================================
|
||||
const GLOBAL_CHAT_ROOM := "global_lobby"
|
||||
const GLOBAL_CHAT_ROOM := "social_global"
|
||||
var _chat_channel = null
|
||||
var _chat_messages: Array = []
|
||||
|
||||
@@ -1311,15 +1311,30 @@ func _join_global_chat() -> void:
|
||||
if not socket.received_channel_message.is_connected(_on_chat_message_received):
|
||||
socket.received_channel_message.connect(_on_chat_message_received)
|
||||
|
||||
# Load history and render (Nakama sends recent messages on join via received_channel_message)
|
||||
# Load history
|
||||
_chat_messages.clear()
|
||||
var history_result = await NakamaManager.client.list_channel_messages_async(NakamaManager.session, _chat_channel.id, 50, false)
|
||||
if not history_result.is_exception() and history_result.messages:
|
||||
var msgs = history_result.messages.duplicate()
|
||||
msgs.reverse() # Oldest to newest
|
||||
for msg in msgs:
|
||||
_add_chat_message(msg, false)
|
||||
|
||||
_trim_old_messages()
|
||||
_refresh_chat_display()
|
||||
|
||||
func _on_chat_message_received(message) -> void:
|
||||
"""Nakama socket signal: a message arrived on any channel."""
|
||||
# message is ApiChannelMessage — use direct property access, NOT .get()
|
||||
if _chat_channel == null or message.channel_id != _chat_channel.id:
|
||||
return
|
||||
|
||||
# Ignore messages from ourselves (we inject them locally for instant feedback)
|
||||
if NakamaManager.session and message.sender_id == NakamaManager.session.user_id:
|
||||
return
|
||||
|
||||
_add_chat_message(message, true)
|
||||
|
||||
func _add_chat_message(message, refresh_display: bool) -> void:
|
||||
# content is a String (JSON) — parse to extract our "msg" field
|
||||
var text: String = ""
|
||||
var parsed = JSON.parse_string(message.content)
|
||||
@@ -1330,8 +1345,10 @@ func _on_chat_message_received(message) -> void:
|
||||
|
||||
# Sender: use username property directly (falls back to first 8 chars of sender_id)
|
||||
var sender: String = message.username
|
||||
if sender.is_empty():
|
||||
if sender.is_empty() and message.sender_id:
|
||||
sender = message.sender_id.substr(0, 8)
|
||||
elif sender.is_empty():
|
||||
sender = "Unknown"
|
||||
|
||||
# Timestamp → HH:MM
|
||||
var ts_str: String = _format_nakama_time(message.create_time)
|
||||
@@ -1340,11 +1357,12 @@ func _on_chat_message_received(message) -> void:
|
||||
"sender": sender,
|
||||
"content": text,
|
||||
"ts": ts_str,
|
||||
"date": message.create_time.substr(0, 10)
|
||||
"date": message.create_time.substr(0, 10) if message.create_time else Time.get_date_string_from_system()
|
||||
})
|
||||
|
||||
_trim_old_messages()
|
||||
_refresh_chat_display()
|
||||
if refresh_display:
|
||||
_trim_old_messages()
|
||||
_refresh_chat_display()
|
||||
|
||||
func _on_chat_send_pressed() -> void:
|
||||
"""Send a message to the global chat channel."""
|
||||
@@ -1355,10 +1373,11 @@ func _on_chat_send_pressed() -> void:
|
||||
chat_input.text = ""
|
||||
chat_input.grab_focus()
|
||||
|
||||
# Instantly show locally for best UX
|
||||
_inject_local_message(text)
|
||||
|
||||
var socket = NakamaManager.socket
|
||||
if not socket or _chat_channel == null:
|
||||
# Offline fallback: show locally only
|
||||
_inject_local_message(text)
|
||||
return
|
||||
|
||||
# Nakama GDScript SDK: write_chat_message_async takes a Dictionary, not a JSON string
|
||||
@@ -1366,8 +1385,6 @@ func _on_chat_send_pressed() -> void:
|
||||
var result = await socket.write_chat_message_async(_chat_channel.id, content)
|
||||
if result.is_exception():
|
||||
push_warning("[Chat] Failed to send message: " + result.get_exception().message)
|
||||
# Still show it locally
|
||||
_inject_local_message(text)
|
||||
|
||||
func _inject_local_message(text: String) -> void:
|
||||
"""Display a message as the local player when offline/fallback."""
|
||||
@@ -1382,9 +1399,9 @@ func _inject_local_message(text: String) -> void:
|
||||
_refresh_chat_display()
|
||||
|
||||
func _trim_old_messages() -> void:
|
||||
"""Remove messages from previous calendar days (daily clear)."""
|
||||
var today: String = Time.get_date_string_from_system()
|
||||
_chat_messages = _chat_messages.filter(func(m): return m.get("date", today) == today)
|
||||
"""Keep only the most recent 100 messages to prevent memory/UI bloat."""
|
||||
if _chat_messages.size() > 100:
|
||||
_chat_messages = _chat_messages.slice(-100)
|
||||
|
||||
func _refresh_chat_display() -> void:
|
||||
"""Re-render the RichTextLabel with all buffered messages."""
|
||||
@@ -1402,20 +1419,28 @@ func _refresh_chat_display() -> void:
|
||||
|
||||
# Scroll to bottom
|
||||
await get_tree().process_frame
|
||||
chat_display.scroll_to_line(chat_display.get_line_count())
|
||||
if chat_display:
|
||||
var scrollbar = chat_display.get_v_scroll_bar()
|
||||
if scrollbar:
|
||||
chat_display.scroll_to_line(chat_display.get_line_count())
|
||||
|
||||
func _format_nakama_time(iso_str: String) -> String:
|
||||
"""Convert Nakama ISO timestamp '2026-04-14T10:30:00Z' → local 'HH:MM'."""
|
||||
# Parse the UTC time components
|
||||
if iso_str.length() < 19:
|
||||
func _format_nakama_time(time_str: String) -> String:
|
||||
"""Convert Nakama time to local 'HH:MM'."""
|
||||
# Nakama returns UNIX epoch as string (e.g. "1714418656") or ISO string.
|
||||
if time_str.is_valid_int():
|
||||
var unix_time = time_str.to_int()
|
||||
var dict = Time.get_time_dict_from_unix_time(unix_time)
|
||||
return "%02d:%02d" % [dict.hour, dict.minute]
|
||||
|
||||
# Fallback for ISO strings or empty
|
||||
if time_str.length() < 19:
|
||||
return _get_local_time_hhmm()
|
||||
var t_parts = iso_str.split("T")
|
||||
var t_parts = time_str.split("T")
|
||||
if t_parts.size() < 2:
|
||||
return _get_local_time_hhmm()
|
||||
var time_part = t_parts[1].replace("Z", "").split(":")
|
||||
if time_part.size() < 2:
|
||||
return _get_local_time_hhmm()
|
||||
# Use UTC hours/minutes directly (simple, avoids TZ complexity in Godot)
|
||||
return "%s:%s" % [time_part[0], time_part[1]]
|
||||
|
||||
func _get_local_time_hhmm() -> String:
|
||||
|
||||
Reference in New Issue
Block a user