import { ChatContentsLayout } from "../ui/components/ChatContentsLayout"; import { DiaLogData, Dialog } from "../data/DialogData"; import Utils from "db://assets/Scripts/Main/Common/Utils"; import { InnerMsgCode } from "db://assets/Scripts/Main/Config/InnerMsgCode"; import { logger } from "db://assets/Scripts/Main/Common/Logger"; /** * 对话管理器 * * 专注于管理对话数据和对话流程,导航功能已迁移至NavigationManager * 在MVP架构中,主要负责Dialog数据的统一管理和UI更新通知 * * @author AI Chat System * @version 2.1.0 (MVP架构优化) */ export class DialogManager { private static _instance: DialogManager; /** * 获取DialogManager的单例实例 * * @returns {DialogManager} 对话管理器实例 * @static */ public static getInstance(): DialogManager { if (!this._instance) { this._instance = new DialogManager(); } return this._instance; } private constructor() { this.dialogData = new DiaLogData(); } /** 对话数据实例 */ private dialogData: DiaLogData; /** 聊天内容布局组件引用 */ public layoutout: ChatContentsLayout; /** * 更新对话内容 * * @param {boolean} isPlayer - 是否为玩家消息 * @param {string} str - 消息内容 * @param {boolean} fromPlayer - 是否来自玩家输入(用于清理对话) */ public updateDialog( isPlayer: boolean, str: string, fromPlayer: boolean = false ): void { if (fromPlayer) { this.dialogData.cleanDialog(); } this.dialogData.pushDialog(isPlayer, str); } /** * 更新分段对话内容(支持多个气泡显示和延迟效果) * * @param {boolean} isPlayer - 是否为玩家消息 * @param {string} str - 消息内容 * @param {boolean} fromPlayer - 是否来自玩家输入(用于清理对话) */ public updateDialogWithSegments( isPlayer: boolean, str: string, fromPlayer: boolean = false ): void { if (fromPlayer) { this.dialogData.cleanDialog(); } // 如果是玩家消息,直接添加单个气泡 if (isPlayer) { this.dialogData.pushDialog(isPlayer, str); logger.log("Dialog updated:", { isPlayer, content: str.substring(0, 50) + "...", }); return; } // 如果是AI消息,进行分段处理 const segments = this.splitMessageIntoSegments(str); if (segments.length <= 1) { // 如果只有一段,直接显示单个气泡 this.dialogData.pushDialog(isPlayer, str); } else { // 多段内容,依次显示多个气泡 this.displaySegmentsWithDelay(segments, isPlayer); } } /** * 将消息分割成多个段落 * @param message 完整消息内容 * @returns 段落数组 */ private splitMessageIntoSegments(message: string): string[] { // 首先按双换行符分割 let segments = message.split(/\n\n+/); // 如果只有一段,则按单换行符分割 if (segments.length === 1) { segments = message.split(/\n+/); } // 过滤空段落并去除首尾空白 return segments .map((segment) => segment.trim()) .filter((segment) => segment.length > 0); } /** * 分段显示消息,每个段落有随机延迟 * @param segments 段落数组 * @param isPlayer 是否为玩家消息 */ private displaySegmentsWithDelay( segments: string[], isPlayer: boolean ): void { segments.forEach((segment, index) => { this.dialogData.pushDialog(isPlayer, segment); }); } /** * 添加加载中的对话 * 显示"..."循环动画表示AI正在回复 */ public addLoadingDialog(): void { this.dialogData.pushDialog(false, "...", true); logger.log("Loading dialog added"); Utils.sendInnerMsg(InnerMsgCode.Chat_DialogRefresh); } public GetPlayerDialog() { return this.dialogData.GetPlayerDialog(); } public GetAIDialog() { return this.dialogData.GetAIDialog(); } /** * 清空当前对话记录 */ public clearDialogs(): void { this.dialogData.cleanDialog(); logger.log("All dialogs cleared"); } /** * 批量设置对话记录 (用于与ChatModel同步) * @param dialogs 对话记录数组 */ public setDialogs(dialogs: Dialog[]): void { this.dialogData.cleanDialog(); dialogs.forEach((dialog) => { this.dialogData.pushDialog( dialog.isPlayer, dialog.content, ); }); logger.log(`DialogManager: Set ${dialogs.length} dialogs`); Utils.sendInnerMsg(InnerMsgCode.Chat_DialogRefresh); } /** * 同步ChatModel的对话数据到DialogManager * @param dialogs ChatModel中的对话数据 */ public syncFromChatModel(dialogs: Dialog[]): void { this.setDialogs(dialogs); logger.log("DialogManager: Synced dialogs from ChatModel"); } }