Files
whale-town/scripts/EnhancedDialogueBox.gd
2025-12-05 19:00:14 +08:00

470 lines
14 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Control
class_name EnhancedDialogueBox
## 增强对话框 UI
## 支持表情符号、群组对话、历史记录等功能
# UI 元素
var message_display: RichTextLabel
var message_input: LineEdit
var send_button: Button
var emoji_button: Button
var history_button: Button
var group_button: Button
var close_button: Button
var target_label: Label
var container: VBoxContainer
var scroll_container: ScrollContainer
# 表情符号选择器
var emoji_picker: Control
var emoji_picker_visible: bool = false
# 历史记录面板
var history_panel: Control
var history_list: ItemList
var history_visible: bool = false
# 群组面板
var group_panel: Control
var group_list: ItemList
var create_group_button: Button
var join_group_button: Button
var group_visible: bool = false
# 管理器引用
var emoji_manager: EmojiManager
var dialogue_filter: DialogueFilter
var group_manager: GroupDialogueManager
var history_manager: DialogueHistoryManager
# 当前对话目标
var current_target_id: String = ""
var current_target_name: String = ""
var is_group_chat: bool = false
# 信号
signal message_sent(target_id: String, message: String, is_group: bool)
signal dialogue_closed()
signal emoji_selected(emoji: String)
func _ready():
"""初始化增强对话框"""
setup_ui()
setup_managers()
connect_signals()
print("EnhancedDialogueBox initialized")
## 设置UI元素
func setup_ui() -> void:
"""设置UI元素和布局"""
# 主容器
container = VBoxContainer.new()
add_child(container)
container.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
# 目标标签
target_label = Label.new()
target_label.text = "对话"
target_label.add_theme_font_size_override("font_size", 16)
container.add_child(target_label)
# 消息显示区域
scroll_container = ScrollContainer.new()
scroll_container.custom_minimum_size = Vector2(400, 300)
container.add_child(scroll_container)
message_display = RichTextLabel.new()
message_display.bbcode_enabled = true
message_display.fit_content = true
scroll_container.add_child(message_display)
# 按钮行
var button_row = HBoxContainer.new()
container.add_child(button_row)
emoji_button = Button.new()
emoji_button.text = "😊"
emoji_button.custom_minimum_size = Vector2(40, 30)
button_row.add_child(emoji_button)
history_button = Button.new()
history_button.text = "历史"
history_button.custom_minimum_size = Vector2(60, 30)
button_row.add_child(history_button)
group_button = Button.new()
group_button.text = "群组"
group_button.custom_minimum_size = Vector2(60, 30)
button_row.add_child(group_button)
close_button = Button.new()
close_button.text = "关闭"
close_button.custom_minimum_size = Vector2(60, 30)
button_row.add_child(close_button)
# 输入行
var input_row = HBoxContainer.new()
container.add_child(input_row)
message_input = LineEdit.new()
message_input.placeholder_text = "输入消息..."
message_input.custom_minimum_size = Vector2(300, 30)
input_row.add_child(message_input)
send_button = Button.new()
send_button.text = "发送"
send_button.custom_minimum_size = Vector2(60, 30)
input_row.add_child(send_button)
# 创建弹出面板
create_emoji_picker()
create_history_panel()
create_group_panel()
## 创建表情符号选择器
func create_emoji_picker() -> void:
"""创建表情符号选择器面板"""
emoji_picker = Control.new()
emoji_picker.visible = false
add_child(emoji_picker)
var picker_bg = NinePatchRect.new()
picker_bg.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
emoji_picker.add_child(picker_bg)
var picker_container = VBoxContainer.new()
picker_container.position = Vector2(10, 10)
picker_container.custom_minimum_size = Vector2(300, 200)
emoji_picker.add_child(picker_container)
# 表情符号网格
var emoji_grid = GridContainer.new()
emoji_grid.columns = 8
picker_container.add_child(emoji_grid)
# 添加常用表情符号
var common_emojis = ["😊", "😢", "😃", "😉", "😛", "😮", "😲", "😐", "😕", "😭", "😂", "😍", "😠", "😡", "😎", "👍", "👎", "👏", "❤️", "🔥"]
for emoji in common_emojis:
var emoji_btn = Button.new()
emoji_btn.text = emoji
emoji_btn.custom_minimum_size = Vector2(30, 30)
emoji_btn.pressed.connect(_on_emoji_button_pressed.bind(emoji))
emoji_grid.add_child(emoji_btn)
## 创建历史记录面板
func create_history_panel() -> void:
"""创建历史记录面板"""
history_panel = Control.new()
history_panel.visible = false
add_child(history_panel)
var history_bg = NinePatchRect.new()
history_bg.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
history_panel.add_child(history_bg)
var history_container = VBoxContainer.new()
history_container.position = Vector2(10, 10)
history_container.custom_minimum_size = Vector2(350, 250)
history_panel.add_child(history_container)
var history_title = Label.new()
history_title.text = "对话历史"
history_title.add_theme_font_size_override("font_size", 14)
history_container.add_child(history_title)
history_list = ItemList.new()
history_list.custom_minimum_size = Vector2(330, 200)
history_container.add_child(history_list)
## 创建群组面板
func create_group_panel() -> void:
"""创建群组管理面板"""
group_panel = Control.new()
group_panel.visible = false
add_child(group_panel)
var group_bg = NinePatchRect.new()
group_bg.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
group_panel.add_child(group_bg)
var group_container = VBoxContainer.new()
group_container.position = Vector2(10, 10)
group_container.custom_minimum_size = Vector2(300, 250)
group_panel.add_child(group_container)
var group_title = Label.new()
group_title.text = "群组管理"
group_title.add_theme_font_size_override("font_size", 14)
group_container.add_child(group_title)
var group_buttons = HBoxContainer.new()
group_container.add_child(group_buttons)
create_group_button = Button.new()
create_group_button.text = "创建群组"
group_buttons.add_child(create_group_button)
join_group_button = Button.new()
join_group_button.text = "加入群组"
group_buttons.add_child(join_group_button)
group_list = ItemList.new()
group_list.custom_minimum_size = Vector2(280, 180)
group_container.add_child(group_list)
## 设置管理器
func setup_managers() -> void:
"""设置各种管理器"""
# 延迟初始化管理器以避免性能问题
call_deferred("_initialize_managers")
func _initialize_managers() -> void:
"""延迟初始化管理器"""
emoji_manager = EmojiManager.new()
add_child(emoji_manager)
dialogue_filter = DialogueFilter.new()
add_child(dialogue_filter)
group_manager = GroupDialogueManager.new()
add_child(group_manager)
history_manager = DialogueHistoryManager.new()
add_child(history_manager)
## 连接信号
func connect_signals() -> void:
"""连接UI信号"""
send_button.pressed.connect(_on_send_button_pressed)
message_input.text_submitted.connect(_on_message_submitted)
emoji_button.pressed.connect(_on_emoji_button_pressed_toggle)
history_button.pressed.connect(_on_history_button_pressed)
group_button.pressed.connect(_on_group_button_pressed)
close_button.pressed.connect(_on_close_button_pressed)
# 管理器信号
dialogue_filter.message_blocked.connect(_on_message_blocked)
group_manager.group_message_received.connect(_on_group_message_received)
## 开始对话
func start_dialogue(target_id: String, target_name: String, is_group: bool = false) -> void:
"""
开始与指定目标的对话
@param target_id: 目标ID
@param target_name: 目标名称
@param is_group: 是否为群组对话
"""
current_target_id = target_id
current_target_name = target_name
is_group_chat = is_group
# 更新UI
if is_group:
target_label.text = "群组: " + target_name
else:
target_label.text = "对话: " + target_name
# 加载历史记录
load_dialogue_history()
# 显示对话框
visible = true
message_input.grab_focus()
## 发送消息
func send_message(message: String) -> void:
"""
发送消息
@param message: 消息内容
"""
if message.strip_edges().is_empty():
return
var sender_id = "player"
# 过滤消息(添加安全检查)
if not dialogue_filter:
show_error_message("对话过滤器未初始化")
return
var filter_result = dialogue_filter.filter_message(sender_id, message)
if not filter_result.allowed:
show_error_message(filter_result.reason)
return
var filtered_message = filter_result.filtered_message
# 转换表情符号
var final_message = EmojiManager.convert_text_to_emoji(filtered_message)
# 发送消息
if is_group_chat:
group_manager.send_group_message(current_target_id, sender_id, final_message)
else:
# 通过NetworkManager发送消息如果连接到服务器
var network_manager = get_node("/root/Main/NetworkManager")
if network_manager and network_manager.is_server_connected():
var dialogue_message = MessageProtocol.create_dialogue_send(sender_id, current_target_id, final_message)
network_manager.send_message(dialogue_message)
message_sent.emit(current_target_id, final_message, false)
# 添加到历史记录
history_manager.add_message_to_history(current_target_id, sender_id, final_message)
# 显示在对话框中
display_message(sender_id, final_message)
# 清空输入框
message_input.text = ""
## 接收消息
func receive_message(sender_id: String, message: String) -> void:
"""
接收消息
@param sender_id: 发送者ID
@param message: 消息内容
"""
# 添加到历史记录
history_manager.add_message_to_history(current_target_id, sender_id, message)
# 显示在对话框中
display_message(sender_id, message)
## 显示消息
func display_message(sender_id: String, message: String) -> void:
"""
在对话框中显示消息
@param sender_id: 发送者ID
@param message: 消息内容
"""
var timestamp = Time.get_datetime_string_from_system()
var sender_name = sender_id if sender_id != "player" else ""
var formatted_message = "[color=gray][%s][/color] [color=blue]%s[/color]: %s\n" % [timestamp, sender_name, message]
message_display.append_text(formatted_message)
# 滚动到底部
await get_tree().process_frame
scroll_container.scroll_vertical = scroll_container.get_v_scroll_bar().max_value
## 加载对话历史
func load_dialogue_history() -> void:
"""加载当前目标的对话历史"""
message_display.clear()
var history = history_manager.get_character_history(current_target_id, 20)
for message_record in history:
var sender_name = message_record.sender if message_record.sender != "player" else ""
var timestamp = Time.get_datetime_string_from_unix_time(message_record.timestamp)
var formatted_message = "[color=gray][%s][/color] [color=blue]%s[/color]: %s\n" % [timestamp, sender_name, message_record.message]
message_display.append_text(formatted_message)
## 显示错误消息
func show_error_message(error_text: String) -> void:
"""
显示错误消息
@param error_text: 错误文本
"""
var error_message = "[color=red]系统: %s[/color]\n" % error_text
message_display.append_text(error_message)
## 信号处理函数
func _on_send_button_pressed() -> void:
"""发送按钮点击处理"""
send_message(message_input.text)
func _on_message_submitted(text: String) -> void:
"""消息输入提交处理"""
send_message(text)
func _on_emoji_button_pressed_toggle() -> void:
"""表情符号按钮点击处理"""
emoji_picker_visible = not emoji_picker_visible
emoji_picker.visible = emoji_picker_visible
# 隐藏其他面板
if emoji_picker_visible:
history_panel.visible = false
group_panel.visible = false
history_visible = false
group_visible = false
func _on_emoji_button_pressed(emoji: String) -> void:
"""表情符号选择处理"""
message_input.text += emoji
emoji_manager.add_to_recent(emoji)
emoji_selected.emit(emoji)
# 隐藏选择器
emoji_picker.visible = false
emoji_picker_visible = false
# 聚焦输入框
message_input.grab_focus()
func _on_history_button_pressed() -> void:
"""历史记录按钮点击处理"""
history_visible = not history_visible
history_panel.visible = history_visible
# 隐藏其他面板
if history_visible:
emoji_picker.visible = false
group_panel.visible = false
emoji_picker_visible = false
group_visible = false
# 更新历史记录列表
update_history_list()
func _on_group_button_pressed() -> void:
"""群组按钮点击处理"""
group_visible = not group_visible
group_panel.visible = group_visible
# 隐藏其他面板
if group_visible:
emoji_picker.visible = false
history_panel.visible = false
emoji_picker_visible = false
history_visible = false
# 更新群组列表
update_group_list()
func _on_close_button_pressed() -> void:
"""关闭按钮点击处理"""
visible = false
dialogue_closed.emit()
func _on_message_blocked(user_id: String, message: String, reason: String) -> void:
"""消息被阻止处理"""
show_error_message("消息被阻止: " + reason)
func _on_group_message_received(group_id: String, sender_id: String, message: String) -> void:
"""群组消息接收处理"""
if group_id == current_target_id and is_group_chat:
receive_message(sender_id, message)
## 更新历史记录列表
func update_history_list() -> void:
"""更新历史记录列表"""
history_list.clear()
var recent_conversations = history_manager.get_recent_conversations(10)
for conversation in recent_conversations:
var item_text = "%s: %s" % [conversation.character_id, conversation.last_message]
if item_text.length() > 50:
item_text = item_text.substr(0, 47) + "..."
history_list.add_item(item_text)
## 更新群组列表
func update_group_list() -> void:
"""更新群组列表"""
group_list.clear()
var player_groups = group_manager.get_player_groups()
for group_info in player_groups:
var item_text = "%s (%d人)" % [group_info.name, group_info.participant_count]
group_list.add_item(item_text)