feat:实现聊天系统核心功能
- 添加 SocketIOClient.gd 实现 Socket.IO 协议封装 - 添加 WebSocketManager.gd 管理连接生命周期和自动重连 - 添加 ChatManager.gd 实现聊天业务逻辑与会话管理 - 支持当前会话缓存(最多 100 条消息) - 支持历史消息按需加载(每次 100 条) - 每次登录/重连自动重置会话缓存 - 客户端频率限制(10 条/分钟) - Token 管理与认证 - 添加 ChatMessage.gd/tscn 消息气泡 UI 组件 - 添加 ChatUI.gd/tscn 聊天界面 - 在 EventNames.gd 添加 7 个聊天事件常量 - 在 AuthManager.gd 添加 game_token 管理方法 - 添加完整的单元测试(128 个测试用例) - test_socketio_client.gd (42 个测试) - test_websocket_manager.gd (38 个测试) - test_chat_manager.gd (48 个测试) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
167
scenes/prefabs/ui/ChatMessage.gd
Normal file
167
scenes/prefabs/ui/ChatMessage.gd
Normal file
@@ -0,0 +1,167 @@
|
||||
extends Panel
|
||||
|
||||
# ============================================================================
|
||||
# ChatMessage.gd - 聊天消息气泡组件
|
||||
# ============================================================================
|
||||
# 显示单条聊天消息的 UI 组件
|
||||
#
|
||||
# 核心职责:
|
||||
# - 显示消息发送者、内容、时间戳
|
||||
# - 区分自己和他人的消息样式
|
||||
# - 自动格式化时间戳
|
||||
#
|
||||
# 使用方式:
|
||||
# var message := chat_message_scene.instantiate()
|
||||
# message.set_message("PlayerName", "Hello!", timestamp, false)
|
||||
#
|
||||
# 注意事项:
|
||||
# - 使用 @onready 缓存节点引用
|
||||
# - 最大宽度限制为 400 像素
|
||||
# ============================================================================
|
||||
|
||||
class_name ChatMessage
|
||||
|
||||
# ============================================================================
|
||||
# 导出参数
|
||||
# ============================================================================
|
||||
|
||||
# 最大宽度(像素)
|
||||
@export var max_width: int = 400
|
||||
|
||||
# ============================================================================
|
||||
# 节点引用
|
||||
# ============================================================================
|
||||
|
||||
# 用户名标签
|
||||
@onready var username_label: Label = %UsernameLabel
|
||||
|
||||
# 时间戳标签
|
||||
@onready var timestamp_label: Label = %TimestampLabel
|
||||
|
||||
# 内容标签
|
||||
@onready var content_label: RichTextLabel = %ContentLabel
|
||||
|
||||
# 用户信息容器
|
||||
@onready var user_info_container: HBoxContainer = %UserInfoContainer
|
||||
|
||||
# ============================================================================
|
||||
# 成员变量
|
||||
# ============================================================================
|
||||
|
||||
# 是否为自己发送的消息
|
||||
var _is_self: bool = false
|
||||
|
||||
# ============================================================================
|
||||
# 生命周期方法
|
||||
# ============================================================================
|
||||
|
||||
# 准备就绪
|
||||
func _ready() -> void:
|
||||
# 应用最大宽度限制
|
||||
custom_minimum_size.x = min(max_width, get_parent().size.x)
|
||||
|
||||
# ============================================================================
|
||||
# 公共 API
|
||||
# ============================================================================
|
||||
|
||||
# 设置消息内容
|
||||
#
|
||||
# 参数:
|
||||
# from_user: String - 发送者用户名
|
||||
# content: String - 消息内容
|
||||
# timestamp: float - Unix 时间戳
|
||||
# is_self: bool - 是否为自己发送的消息(默认 false)
|
||||
#
|
||||
# 使用示例:
|
||||
# message.set_message("Alice", "Hello!", 1703500800.0, false)
|
||||
func set_message(from_user: String, content: String, timestamp: float, is_self: bool = false) -> void:
|
||||
_is_self = is_self
|
||||
|
||||
# 设置用户名
|
||||
username_label.text = from_user
|
||||
|
||||
# 设置内容
|
||||
content_label.text = content
|
||||
|
||||
# 设置时间戳
|
||||
timestamp_label.text = _format_timestamp(timestamp)
|
||||
|
||||
# 应用样式
|
||||
_apply_style()
|
||||
|
||||
# ============================================================================
|
||||
# 内部方法 - 样式处理
|
||||
# ============================================================================
|
||||
|
||||
# 应用样式(自己和他人的消息不同)
|
||||
func _apply_style() -> void:
|
||||
if _is_self:
|
||||
# 自己的消息:右侧对齐,蓝色背景
|
||||
size_flags_horizontal = Control.SIZE_SHRINK_END
|
||||
user_info_container.alignment = BoxContainer.ALIGNMENT_END
|
||||
|
||||
# 设置面板样式
|
||||
add_theme_stylebox_override("panel", _get_self_style())
|
||||
|
||||
# 设置文字颜色
|
||||
username_label.add_theme_color_override("font_color", Color.WHITE)
|
||||
timestamp_label.add_theme_color_override("font_color", Color(0.7, 0.7, 0.7))
|
||||
else:
|
||||
# 他人的消息:左侧对齐,灰色背景
|
||||
size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
user_info_container.alignment = BoxContainer.ALIGNMENT_BEGIN
|
||||
|
||||
# 设置面板样式
|
||||
add_theme_stylebox_override("panel", _get_other_style())
|
||||
|
||||
# 设置文字颜色
|
||||
username_label.add_theme_color_override("font_color", Color(0.2, 0.4, 0.8))
|
||||
timestamp_label.add_theme_color_override("font_color", Color(0.5, 0.5, 0.5))
|
||||
|
||||
# 获取自己消息的样式
|
||||
func _get_self_style() -> StyleBoxFlat:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.2, 0.6, 1.0, 0.3)
|
||||
style.corner_radius_top_left = 10
|
||||
style.corner_radius_top_right = 10
|
||||
style.corner_radius_bottom_left = 10
|
||||
style.corner_radius_bottom_right = 2
|
||||
style.content_margin_left = 10
|
||||
style.content_margin_right = 10
|
||||
style.content_margin_top = 8
|
||||
style.content_margin_bottom = 8
|
||||
return style
|
||||
|
||||
# 获取他人消息的样式
|
||||
func _get_other_style() -> StyleBoxFlat:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.9, 0.9, 0.9, 0.5)
|
||||
style.corner_radius_top_left = 10
|
||||
style.corner_radius_top_right = 10
|
||||
style.corner_radius_bottom_left = 2
|
||||
style.corner_radius_bottom_right = 10
|
||||
style.content_margin_left = 10
|
||||
style.content_margin_right = 10
|
||||
style.content_margin_top = 8
|
||||
style.content_margin_bottom = 8
|
||||
return style
|
||||
|
||||
# ============================================================================
|
||||
# 内部方法 - 工具函数
|
||||
# ============================================================================
|
||||
|
||||
# 格式化时间戳
|
||||
#
|
||||
# 参数:
|
||||
# timestamp: float - Unix 时间戳
|
||||
#
|
||||
# 返回值:
|
||||
# String - 格式化的时间字符串
|
||||
func _format_timestamp(timestamp: float) -> String:
|
||||
if timestamp == 0:
|
||||
return ""
|
||||
|
||||
var datetime := Time.get_datetime_dict_from_unix_time(timestamp)
|
||||
|
||||
# 格式化为 HH:MM
|
||||
return "%02d:%02d" % [datetime.hour, datetime.minute]
|
||||
Reference in New Issue
Block a user