2025-08-27 16:12:19 +08:00
|
|
|
import { VideoEmotion, purchase } from "../../schema/schema";
|
|
|
|
|
import { Dialog } from "./DialogData";
|
2025-09-01 16:26:37 +08:00
|
|
|
import { ConfigManager } from "../manager/ConfigManager";
|
2025-09-10 16:43:46 +08:00
|
|
|
import { DataId, DataManager } from "./DataManager";
|
|
|
|
|
import { GirlData } from "./GirlData";
|
2025-08-27 16:12:19 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 单个角色的聊天数据结构
|
|
|
|
|
*/
|
|
|
|
|
export interface RoleChatData {
|
2025-09-10 16:43:46 +08:00
|
|
|
categoryId: string;
|
|
|
|
|
girlId: number;
|
2025-08-27 16:12:19 +08:00
|
|
|
dialogs: Dialog[];
|
|
|
|
|
currentEmotion: VideoEmotion;
|
|
|
|
|
lastActiveTime: Date;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 聊天数据模型类 (多角色管理器)
|
|
|
|
|
*
|
|
|
|
|
* 负责管理多个角色的聊天相关数据,包括:
|
|
|
|
|
* - 多个角色的数据和配置
|
|
|
|
|
* - 各角色独立的对话历史记录
|
|
|
|
|
* - 各角色独立的情绪状态
|
|
|
|
|
* - 视频配置管理
|
|
|
|
|
* - 角色切换和数据持久化
|
|
|
|
|
*
|
|
|
|
|
* 这是MVP架构中的Model层,专注于多角色数据管理和业务逻辑
|
|
|
|
|
*/
|
|
|
|
|
export class ChatModel {
|
|
|
|
|
// 存储所有角色的数据
|
|
|
|
|
private rolesData: Map<number, RoleChatData> = new Map();
|
|
|
|
|
|
|
|
|
|
// 当前活跃的角色ID
|
2025-09-10 16:43:46 +08:00
|
|
|
private currentGirlId: number | null = null;
|
2025-08-27 16:12:19 +08:00
|
|
|
|
|
|
|
|
// 最大缓存角色数量(内存管理)
|
|
|
|
|
private maxCachedRoles: number = 10;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 初始化或切换到指定角色
|
2025-09-10 16:43:46 +08:00
|
|
|
* @param girlId 角色ID
|
2025-08-27 16:12:19 +08:00
|
|
|
* @returns 是否成功
|
|
|
|
|
*/
|
2025-09-10 16:43:46 +08:00
|
|
|
public initializeRole(categoryId: string, girlId: number): boolean {
|
|
|
|
|
if (girlId <= 0) {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.error("ChatModel: Invalid roleId provided");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果角色数据已存在,直接切换
|
2025-09-10 16:43:46 +08:00
|
|
|
if (this.rolesData.has(girlId)) {
|
|
|
|
|
this.currentGirlId = girlId;
|
|
|
|
|
this.updateLastActiveTime(girlId);
|
|
|
|
|
console.log(`ChatModel: Switched to existing role ${girlId}`);
|
2025-08-27 16:12:19 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建新的角色数据
|
2025-09-10 16:43:46 +08:00
|
|
|
const newRoleData = this.createRoleData(categoryId, girlId);
|
2025-08-27 16:12:19 +08:00
|
|
|
if (newRoleData) {
|
|
|
|
|
// 内存管理:如果超过最大缓存数量,清理最久未使用的角色
|
|
|
|
|
this.manageMemory();
|
|
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
this.rolesData.set(girlId, newRoleData);
|
|
|
|
|
this.currentGirlId = girlId;
|
|
|
|
|
console.log(`ChatModel: Initialized new role ${girlId}`);
|
2025-08-27 16:12:19 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
/**
|
|
|
|
|
* 检查是否有指定角色的数据
|
|
|
|
|
* @param roleId 角色ID
|
|
|
|
|
*/
|
|
|
|
|
public hasRoleData(roleId: number): boolean {
|
|
|
|
|
return this.rolesData.has(roleId);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 16:12:19 +08:00
|
|
|
/**
|
|
|
|
|
* 切换到指定角色(不存在则初始化)
|
|
|
|
|
* @param roleId 角色ID
|
|
|
|
|
* @returns 是否成功
|
|
|
|
|
*/
|
2025-09-10 16:43:46 +08:00
|
|
|
public switchToRole(categoryId: string, roleId: number): boolean {
|
|
|
|
|
return this.initializeRole(categoryId, roleId);
|
2025-08-27 16:12:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 创建新的角色数据
|
2025-09-10 16:43:46 +08:00
|
|
|
* @param girlId 角色ID
|
2025-08-27 16:12:19 +08:00
|
|
|
* @returns 角色数据对象
|
|
|
|
|
*/
|
2025-09-10 16:43:46 +08:00
|
|
|
private createRoleData(
|
|
|
|
|
categoryId: string,
|
|
|
|
|
girlId: number
|
|
|
|
|
): RoleChatData | null {
|
2025-08-27 16:12:19 +08:00
|
|
|
try {
|
|
|
|
|
// 加载角色基础数据
|
|
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
|
|
|
|
const chatTotalCount = girlData.getChatTotalCount(categoryId, girlId);
|
|
|
|
|
|
|
|
|
|
//const roleData = ConfigManager.tables.TbGirls.get(roleId);
|
|
|
|
|
//const roleDetail = ConfigManager.tables.TbGirlsDetail.get(roleId);
|
|
|
|
|
|
|
|
|
|
if (!girlData) {
|
|
|
|
|
console.error(`ChatModel: Role data not found for roleId ${girlId}`);
|
2025-08-27 16:12:19 +08:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Todo:未接入后端数据 待补充
|
|
|
|
|
// 创建角色数据对象
|
|
|
|
|
const newRoleData: RoleChatData = {
|
2025-09-10 16:43:46 +08:00
|
|
|
girlId: girlId,
|
|
|
|
|
categoryId: categoryId,
|
2025-08-27 16:12:19 +08:00
|
|
|
dialogs: [],
|
|
|
|
|
currentEmotion: VideoEmotion.calm_down,
|
|
|
|
|
lastActiveTime: new Date(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return newRoleData;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(
|
2025-09-10 16:43:46 +08:00
|
|
|
`ChatModel: Failed to create role data for ${girlId}:`,
|
2025-08-27 16:12:19 +08:00
|
|
|
error
|
|
|
|
|
);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 内存管理:清理最久未使用的角色数据
|
|
|
|
|
*/
|
|
|
|
|
private manageMemory(): void {
|
|
|
|
|
if (this.rolesData.size < this.maxCachedRoles) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找出最久未使用的角色
|
|
|
|
|
let oldestRoleId: number | null = null;
|
|
|
|
|
let oldestTime: Date = new Date();
|
|
|
|
|
|
|
|
|
|
for (const [roleId, roleData] of this.rolesData.entries()) {
|
|
|
|
|
if (roleData.lastActiveTime < oldestTime) {
|
|
|
|
|
oldestTime = roleData.lastActiveTime;
|
|
|
|
|
oldestRoleId = roleId;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (oldestRoleId !== null) {
|
|
|
|
|
this.rolesData.delete(oldestRoleId);
|
|
|
|
|
console.log(`ChatModel: Cleaned up unused role ${oldestRoleId} data`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 更新角色最后活跃时间
|
|
|
|
|
* @param roleId 角色ID
|
|
|
|
|
*/
|
|
|
|
|
private updateLastActiveTime(roleId: number): void {
|
|
|
|
|
const roleData = this.rolesData.get(roleId);
|
|
|
|
|
if (roleData) {
|
|
|
|
|
roleData.lastActiveTime = new Date();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取当前活跃角色ID
|
|
|
|
|
*/
|
|
|
|
|
public getCurrentRoleId(): number | null {
|
2025-09-10 16:43:46 +08:00
|
|
|
return this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取当前角色数据
|
|
|
|
|
*/
|
|
|
|
|
public getCurrentRoleData(): RoleChatData | null {
|
2025-09-10 16:43:46 +08:00
|
|
|
if (!this.currentGirlId) {
|
2025-08-27 16:12:19 +08:00
|
|
|
return null;
|
|
|
|
|
}
|
2025-09-10 16:43:46 +08:00
|
|
|
return this.rolesData.get(this.currentGirlId) || null;
|
2025-08-27 16:12:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取对话记录
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
*/
|
|
|
|
|
public getDialogs(roleId?: number): Dialog[] {
|
2025-09-10 16:43:46 +08:00
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
return roleData ? [...roleData.dialogs] : []; // 返回副本避免外部修改
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 添加对话记录
|
|
|
|
|
* @param isPlayer 是否为玩家消息
|
|
|
|
|
* @param content 消息内容
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
*/
|
|
|
|
|
public addDialog(isPlayer: boolean, content: string, roleId?: number): void {
|
2025-09-10 16:43:46 +08:00
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
console.warn("ChatModel: Cannot add dialog - no active role");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!content || content.trim() === "") {
|
|
|
|
|
console.warn("ChatModel: Cannot add empty dialog content");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
if (!roleData) {
|
|
|
|
|
console.warn(`ChatModel: Role data not found for roleId ${targetRoleId}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const dialog: Dialog = {
|
|
|
|
|
isPlayer: isPlayer,
|
|
|
|
|
content: content.trim(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
roleData.dialogs.push(dialog);
|
|
|
|
|
this.updateLastActiveTime(targetRoleId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 清空对话记录
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
*/
|
|
|
|
|
public clearDialogs(roleId?: number): void {
|
2025-09-10 16:43:46 +08:00
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
console.warn("ChatModel: Cannot clear dialogs - no active role");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
if (roleData) {
|
|
|
|
|
roleData.dialogs = [];
|
|
|
|
|
this.updateLastActiveTime(targetRoleId);
|
|
|
|
|
console.log(`ChatModel: Dialogs cleared for role ${targetRoleId}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取当前情绪状态
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
*/
|
|
|
|
|
public getCurrentEmotion(roleId?: number): VideoEmotion {
|
2025-09-10 16:43:46 +08:00
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
return VideoEmotion.calm_down;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
return roleData ? roleData.currentEmotion : VideoEmotion.calm_down;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 设置当前情绪状态
|
|
|
|
|
* @param emotion 新的情绪状态
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
*/
|
|
|
|
|
public setCurrentEmotion(emotion: VideoEmotion, roleId?: number): void {
|
2025-09-10 16:43:46 +08:00
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
console.warn("ChatModel: Cannot set emotion - no active role");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
if (!roleData) {
|
|
|
|
|
console.warn(`ChatModel: Role data not found for roleId ${targetRoleId}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (roleData.currentEmotion !== emotion) {
|
|
|
|
|
const oldEmotion = roleData.currentEmotion;
|
|
|
|
|
roleData.currentEmotion = emotion;
|
|
|
|
|
this.updateLastActiveTime(targetRoleId);
|
|
|
|
|
console.log(
|
|
|
|
|
`ChatModel: Role ${targetRoleId} emotion changed from ${VideoEmotion[oldEmotion]} to ${VideoEmotion[emotion]}`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-27 16:35:26 +08:00
|
|
|
* 根据情绪获取对应的视频(如果有多个视频,随机返回一个)
|
2025-08-27 16:12:19 +08:00
|
|
|
* @param emotion 目标情绪
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
2025-09-10 16:43:46 +08:00
|
|
|
* @returns 匹配的视频url
|
2025-08-27 16:12:19 +08:00
|
|
|
*/
|
2025-09-10 16:43:46 +08:00
|
|
|
public getVideoByEmotion(emotion: VideoEmotion, roleId?: number): string {
|
|
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
if (!roleData) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2025-09-10 16:43:46 +08:00
|
|
|
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
|
|
|
|
const allvideoIDs = girlData.getAllDisplayGrilVideoId(
|
|
|
|
|
roleData.categoryId,
|
|
|
|
|
roleData.girlId
|
2025-08-27 16:12:19 +08:00
|
|
|
);
|
2025-09-10 16:43:46 +08:00
|
|
|
let targetIds: number[] = [];
|
|
|
|
|
for (let i = 0; i < allvideoIDs.length; i++) {
|
|
|
|
|
const element = allvideoIDs[i];
|
|
|
|
|
if (
|
|
|
|
|
girlData.getGrilVideoEmotion(
|
|
|
|
|
roleData.categoryId,
|
|
|
|
|
roleData.girlId,
|
|
|
|
|
element
|
|
|
|
|
) === emotion
|
|
|
|
|
) {
|
|
|
|
|
targetIds.push(allvideoIDs[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-27 16:35:26 +08:00
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
if (targetIds.length === 0) {
|
2025-08-27 16:35:26 +08:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果只有一个匹配的视频,直接返回
|
2025-09-10 16:43:46 +08:00
|
|
|
if (targetIds.length === 1) {
|
|
|
|
|
return girlData.getGrilVideoPath(
|
|
|
|
|
roleData.categoryId,
|
|
|
|
|
roleData.girlId,
|
|
|
|
|
targetIds[0]
|
|
|
|
|
);
|
2025-08-27 16:35:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果有多个匹配的视频,随机选择一个
|
2025-09-10 16:43:46 +08:00
|
|
|
const randomIndex = Math.floor(Math.random() * targetIds.length);
|
|
|
|
|
return girlData.getGrilVideoPath(
|
|
|
|
|
roleData.categoryId,
|
|
|
|
|
roleData.girlId,
|
|
|
|
|
targetIds[randomIndex]
|
|
|
|
|
);
|
2025-08-27 16:12:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取默认视频(第一个视频或平静状态视频)
|
2025-09-10 16:43:46 +08:00
|
|
|
* @param girlId 角色ID,不传则使用当前角色
|
2025-08-27 16:12:19 +08:00
|
|
|
*/
|
2025-09-10 16:43:46 +08:00
|
|
|
public getDefaultVideo(): string {
|
|
|
|
|
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
|
|
|
|
const roleData = this.rolesData.get(this.currentGirlId);
|
2025-08-27 16:12:19 +08:00
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
const allvideoIDs = girlData.getAllDisplayGrilVideoId(
|
|
|
|
|
roleData.categoryId,
|
|
|
|
|
roleData.girlId
|
2025-08-27 16:12:19 +08:00
|
|
|
);
|
2025-09-10 16:43:46 +08:00
|
|
|
let targetId: number = -1;
|
|
|
|
|
for (let i = 0; i < allvideoIDs.length; i++) {
|
|
|
|
|
const element = allvideoIDs[i];
|
|
|
|
|
if (
|
|
|
|
|
girlData.getGrilVideoEmotion(
|
|
|
|
|
roleData.categoryId,
|
|
|
|
|
roleData.girlId,
|
|
|
|
|
element
|
|
|
|
|
) === VideoEmotion.calm_down
|
|
|
|
|
) {
|
|
|
|
|
targetId = element;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (targetId == -1) {
|
|
|
|
|
return null;
|
|
|
|
|
} else {
|
|
|
|
|
return girlData.getGrilVideoPath(
|
|
|
|
|
roleData.categoryId,
|
|
|
|
|
roleData.girlId,
|
|
|
|
|
targetId
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-08-27 16:12:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取对话数量
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
*/
|
|
|
|
|
public getDialogCount(roleId?: number): number {
|
2025-09-10 16:43:46 +08:00
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
return roleData ? roleData.dialogs.length : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取最后一条对话
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
*/
|
|
|
|
|
public getLastDialog(roleId?: number): Dialog | null {
|
2025-09-10 16:43:46 +08:00
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
if (!roleData || roleData.dialogs.length === 0) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return roleData.dialogs[roleData.dialogs.length - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 重置所有数据到初始状态
|
|
|
|
|
*/
|
|
|
|
|
public reset(): void {
|
|
|
|
|
this.rolesData.clear();
|
2025-09-10 16:43:46 +08:00
|
|
|
this.currentGirlId = null;
|
2025-08-27 16:12:19 +08:00
|
|
|
console.log(
|
|
|
|
|
"ChatModel: All role data cleared and model reset to initial state"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 重置指定角色的数据
|
|
|
|
|
* @param roleId 角色ID
|
|
|
|
|
*/
|
|
|
|
|
public resetRole(roleId: number): void {
|
|
|
|
|
if (this.rolesData.has(roleId)) {
|
|
|
|
|
this.rolesData.delete(roleId);
|
|
|
|
|
|
|
|
|
|
// 如果删除的是当前角色,清空当前角色ID
|
2025-09-10 16:43:46 +08:00
|
|
|
if (this.currentGirlId === roleId) {
|
|
|
|
|
this.currentGirlId = null;
|
2025-08-27 16:12:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log(`ChatModel: Role ${roleId} data cleared`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 验证当前模型状态
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
*/
|
|
|
|
|
public validate(roleId?: number): boolean {
|
2025-09-10 16:43:46 +08:00
|
|
|
const targetRoleId = roleId || this.currentGirlId;
|
2025-08-27 16:12:19 +08:00
|
|
|
if (!targetRoleId) {
|
|
|
|
|
console.error("ChatModel: No active role");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roleData = this.rolesData.get(targetRoleId);
|
|
|
|
|
if (!roleData) {
|
|
|
|
|
console.error(`ChatModel: Role data not found for ${targetRoleId}`);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取所有角色数据摘要
|
|
|
|
|
*/
|
|
|
|
|
public getAllRolesData(): Map<number, RoleChatData> {
|
|
|
|
|
return new Map(this.rolesData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取缓存的角色数量
|
|
|
|
|
*/
|
|
|
|
|
public getCachedRoleCount(): number {
|
|
|
|
|
return this.rolesData.size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取所有角色ID列表
|
|
|
|
|
*/
|
|
|
|
|
public getAllRoleIds(): number[] {
|
|
|
|
|
return Array.from(this.rolesData.keys());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 清除指定角色的数据(外部调用接口)
|
|
|
|
|
* @param roleId 角色ID
|
|
|
|
|
*/
|
|
|
|
|
public clearRoleData(roleId: number): void {
|
|
|
|
|
this.resetRole(roleId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 设置最大缓存角色数量
|
|
|
|
|
* @param maxCount 最大缓存数量
|
|
|
|
|
*/
|
|
|
|
|
public setMaxCachedRoles(maxCount: number): void {
|
|
|
|
|
if (maxCount > 0) {
|
|
|
|
|
this.maxCachedRoles = maxCount;
|
|
|
|
|
console.log(`ChatModel: Max cached roles set to ${maxCount}`);
|
|
|
|
|
|
|
|
|
|
// 如果当前缓存超过新限制,清理多余的
|
|
|
|
|
this.manageMemory();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取默认聊天次数限制
|
|
|
|
|
* TODO: 以后从后端获取,目前默认返回10
|
|
|
|
|
* @returns 默认聊天次数限制
|
|
|
|
|
*/
|
|
|
|
|
private getDefaultChatLimit(): number {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查角色是否还有剩余聊天次数
|
|
|
|
|
* @param roleId 角色ID,不传则使用当前角色
|
|
|
|
|
* @returns 是否可以继续聊天
|
|
|
|
|
*/
|
|
|
|
|
public canChat(roleId?: number): boolean {
|
2025-09-11 00:03:22 +08:00
|
|
|
//return false;
|
2025-09-10 16:43:46 +08:00
|
|
|
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
|
|
|
|
const roleData = this.rolesData.get(this.currentGirlId);
|
2025-09-17 23:33:03 +08:00
|
|
|
return girlData.isCanChat(
|
2025-09-17 18:51:08 +08:00
|
|
|
roleData.categoryId,
|
|
|
|
|
roleData.girlId
|
2025-08-27 16:12:19 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|