/** * 技师数据,统一访问入口 */ import { BaseData } from "./BaseData"; import { GirlBriefData } from "./GirlBriefData"; import { GirlDetailData } from "./GirlDetailData"; import { GirlUnlockData } from "./GirlUnlockData"; import { GirlChatData } from "./GirlChatData"; import { GirlFavorabilityData } from "./GirlFavorabilityData"; import { GirlRankData } from "./GirlRankData"; import { GirlOtherData } from "./GirlOtherData"; import { DataId } from "./DataManager"; import proto from "db://assets/Scripts/proto/proto.pb.js"; import { PriceType } from "../../schema/schema"; import { logger } from "db://assets/Scripts/Main/Common/Logger"; // 分类的数据结构 interface CategoryBucket { // 技师的简要数据 briefs: Map; // 技师的详细数据 details: Map; // 技师的解锁数据 unlocks: Map; // 技师的聊天数据 chats: Map; // 技师的好感度数据 favorability: Map; // 技师的其他数据 other: Map; // 技师的id girlIds: number[]; } // 每日推荐专用分类 const DAILY_BUCKET = "__daily__"; export class GirlData extends BaseData { // 大分类 private _categories = new Map(); // 排行榜数据 private _rankData: GirlRankData; constructor() { super(); this._rankData = new GirlRankData(); this._rankData.init?.(DataId.GirlRank); } public reset(): void { this._categories.clear(); this._rankData.clear(); } public clear(): void { this._categories.clear(); this._rankData.clear(); } public destroy(): void { super.destroy(); this._categories = null; this._rankData = null; } /** 保障 _categories 存在 */ private ensureCategories(): Map { if (!this._categories) { this._categories = new Map(); } return this._categories; } /** 获取或创建分类桶 */ private ensureBucket(categoryId: string): CategoryBucket { const cats = this.ensureCategories(); let bucket = cats.get(categoryId); if (!bucket) { bucket = { briefs: new Map(), details: new Map(), unlocks: new Map(), chats: new Map(), favorability: new Map(), other: new Map(), girlIds: [], }; cats.set(categoryId, bucket); } return bucket; } /** 取分类下的全部 girlIds(若分类不存在返回空数组) */ public getGirlIds(categoryId: string): number[] { const b = this.ensureCategories().get(categoryId); return b ? b.girlIds : []; } /** 保存技师列表 */ public setGirlList(categoryId: string, data: proto.cs.ICSGetGirlListRes): void { if (!data) return; this.setGirlBrief(categoryId, data.girls); this.setGirlUnlock(categoryId, data.girls); this.setGirlFavorability(categoryId, data.girls); this.setGirlOther(categoryId, data.girls); const bucket = this.ensureBucket(categoryId); logger.log("保存类别 ", categoryId, " 的技师列表: ", bucket); } /** 保存技师详细数据 */ public setGirlDetailData(categoryId: string, data: proto.cs.ICSGetGirlDetailRes): void { if (!data) return; let details = []; details.push(data.girl); this.setGirlBrief(categoryId, details); this.setGirlDetail(categoryId, details); this.setGirlUnlock(categoryId, details); this.setGirlChat(categoryId, details); this.setGirlFavorability(categoryId, details); this.setGirlOther(categoryId, details); const bucket = this.ensureBucket(categoryId); logger.log("保存类别 ", categoryId, " 的详细数据: ", bucket); } /** 保存可聊天的技师数据 */ public setCanChatGirlData(data: proto.cs.ICSGetLastChatListRes): void { if (!data) return; let canChatList = data.LastChatList; // 遍历 for (const oneData of canChatList) { let briefData = oneData.girl; let categoryId = briefData.category; this.mergeOneBrief(categoryId.toString(), briefData); this.refreshGirlUnlock(oneData); this.refreshGirlFavorability(oneData); this.refreshGirlChat(oneData); } const cats = this.ensureCategories(); logger.log("保存可聊天的技师数据: ", cats); } /** 保存收藏列表 */ public setBookmarkGirlList(data: proto.cs.ICSGetBookmarkRes): void { if (!data) return; let arrayData = data.girls; // 遍历 for (const oneData of arrayData) { let briefData = oneData.girl; let categoryId = briefData.category; this.mergeOneBrief(categoryId.toString(), briefData); let theArray = []; theArray.push(oneData); this.setGirlUnlock(categoryId.toString(), theArray); this.setGirlFavorability(categoryId.toString(), theArray); this.setGirlOther(categoryId.toString(), theArray); } const cats = this.ensureCategories(); logger.log("保存收藏列表后,大分类的数据: ", cats); } /** --------------------------------------------------------- 每日推荐 --------------------------------------------------------- */ /** 保存每日推荐:放入特殊分类 DAILY_BUCKET,并维护 id 索引 */ public setDailyRecommend(data: proto.cs.ICSDailyRecommendRes): void { if (!data) return; this.mergeOneBrief(DAILY_BUCKET, data.girl); const bucket = this.ensureBucket(DAILY_BUCKET); logger.log("保存每日推荐: ", bucket); } /** 判断每日推荐是否存在 */ public isDailyRecommendIn(): boolean { const bucket = this.ensureCategories().get(DAILY_BUCKET); if (!bucket) return false; return bucket.girlIds.length > 0; } /** 获取推荐id */ public getRecommendGirlId(): number { const bucket = this.ensureBucket(DAILY_BUCKET); const girlIds = bucket.girlIds; const length = girlIds.length; if (length <= 0) return 0; return girlIds[length - 1]; } /** 获取每日推荐的简要数据 */ private getRecommendGrilBrief(): GirlBriefData | null { const recId = this.getRecommendGirlId(); if (recId <= 0) return null; const data = this.getGrilBrief(DAILY_BUCKET, recId); return data; } /** 获取名字 */ public getRecommendGrilName(): string { let oneData = this.getRecommendGrilBrief(); if (!oneData) return ""; return oneData.getGrilName(); } /** 获取头像路径 */ public getRecommendGrilAvatar(): string { let oneData = this.getRecommendGrilBrief(); if (!oneData) return ""; return oneData.getGrilAvatar(); } /** --------------------------------------------------------- 技师的排行榜数据 --------------------------------------------------------- */ /** 清空 排行榜数据 */ public clearGirlRank(): void { if (!this._rankData) return; this._rankData.clear(); } /** 保存 排行榜数据 */ public setGirlRank(rankType: proto.cs.EnmRankType, data: proto.cs.ICSGetRankRes): void { if (!data) return; let arrayData = data.girls; // 遍历 for (const oneData of arrayData) { let briefData = oneData.girl; let categoryId = briefData.category; this.mergeOneBrief(categoryId.toString(), briefData); let theArray = []; theArray.push(oneData); this.setGirlUnlock(categoryId.toString(), theArray); this.setGirlFavorability(categoryId.toString(), theArray); this.setGirlOther(categoryId.toString(), theArray); } this._rankData.setRankData(rankType, arrayData); const cats = this.ensureCategories(); logger.log("保存排行榜数据后,大分类的数据: ", cats); } /** 添加 排行榜数据 */ public addRankData(rankType: proto.cs.EnmRankType, data: proto.cs.ICSGetRankRes): void { if (!data) return; let arrayData = data.girls; // 遍历 for (const oneData of arrayData) { let briefData = oneData.girl; let categoryId = briefData.category; this.mergeOneBrief(categoryId.toString(), briefData); let theArray = []; theArray.push(oneData); this.setGirlUnlock(categoryId.toString(), theArray); this.setGirlFavorability(categoryId.toString(), theArray); this.setGirlOther(categoryId.toString(), theArray); } this._rankData.addRankData(rankType, arrayData); const cats = this.ensureCategories(); logger.log("添加排行榜数据后,大分类的数据: ", cats); } /** 获取排行榜技师 id,根据排行榜类型 */ public getRankIdsByType(rankType: proto.cs.EnmRankType): number[] { if (!this._rankData) return []; const ids = this._rankData.getRankIdsByType(rankType); return ids; } /** --------------------------------------------------------- 技师的简要数据 --------------------------------------------------------- */ /** * 合并一个简要数据到指定分类;并维护 girlIds 顺序(去重追加) */ private mergeOneBrief(categoryId: string, data: proto.cs.IGirls): void { if (!data) return; const bucket = this.ensureBucket(categoryId); // 用一个临时 Set 保存已有的 id,加速去重 const existed = new Set(bucket.girlIds); let id = data.id; const one = this.parseOneGirlBrief(data); if (!one) return; bucket.briefs.set(id, one); if (!existed.has(id)) { bucket.girlIds.push(id); } } /** * 合并一批简要数据到指定分类;并维护 girlIds 顺序(去重追加) */ private mergeBriefs( categoryId: string, respOrList: proto.cs.IGirlData[] ): void { if (!respOrList) return; const bucket = this.ensureBucket(categoryId); // 用一个临时 Set 保存已有的 id,加速去重 const existed = new Set(bucket.girlIds); for (const g of respOrList) { const one = this.parseOneGirlBrief(g.girl); if (!one) continue; bucket.briefs.set(g.id, one); if (!existed.has(g.id)) { bucket.girlIds.push(g.id); existed.add(g.id); } } } private parseOneGirlBrief(data: proto.cs.IGirls): GirlBriefData | null { if (!data) return null; let oneData = new GirlBriefData(); oneData.init?.(DataId.GirlBrief); oneData.setData(data); return oneData; } /** 保存技师的简要数据 */ private setGirlBrief(categoryId: string, data: proto.cs.IGirlData[]): void { this.mergeBriefs(categoryId, data); } /** 取某分类 + girlId 的简要数据 */ private getGrilBrief( categoryId: string, girlId: number ): GirlBriefData | null { const b = this.ensureCategories().get(categoryId); if (!b) return null; return b.briefs.get(girlId) ?? null; } /** 技师的简要信息是否存在 */ public isGirlBriefIn(categoryId: string, girlId: number): boolean { const b = this.ensureCategories().get(categoryId); if (!b) return false; return b.briefs.has(girlId); } /** 获取名字键 */ public getGrilName(categoryId: string, girlId: number): string { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return ""; return oneData.getGrilName(); } /** 获取年龄 */ public getGrilAge(categoryId: string, girlId: number): string { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return "0"; return oneData.getGrilAge(); } /** 获取主题枚举 */ public getGrilCategory(categoryId: string, girlId: number): number { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilCategory(); } /** 获取标签键 */ public getGrilTagKey(categoryId: string, girlId: number): string { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return ""; return oneData.getGrilTagKey(); } /** 获取付费类型 */ public getGrilPriceType(categoryId: string, girlId: number): number { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilPriceType(); } /** 技师是否免费类型 */ public isGirlFreeType(categoryId: string, girlId: number): boolean { let priceType = this.getGrilPriceType(categoryId, girlId); return priceType == PriceType.free; } /** 技师是否付费类型 */ public isGirlPayType(categoryId: string, girlId: number): boolean { let priceType = this.getGrilPriceType(categoryId, girlId); return priceType == PriceType.pay; } /** 获取原来的价格,除100 */ public getGrilOriginalPrice(categoryId: string, girlId: number): number { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return 0; let price = oneData.getGrilPrice(); return price / 100; } /** 获取价格 */ public getGrilPrice(categoryId: string, girlId: number): number { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilPrice(); } /** 获取VIP能否解锁 */ public getGrilVipUnlock(categoryId: string, girlId: number): number { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilVipUnlock(); } /** 获取头像路径 */ public getGrilAvatar(categoryId: string, girlId: number): string { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return ""; return oneData.getGrilAvatar(); } /** 获取list头像路径 */ public getGrilListAvatar(categoryId: string, girlId: number): string { let oneData = this.getGrilBrief(categoryId, girlId); if (!oneData) return ""; return oneData.getGrilListAvatar(); } /** 获取主题枚举,根据 id */ public getGrilCategoryById(girlId: number): number { const cats = this.ensureCategories(); // 遍历 for (const bucket of cats.values()) { // 先查简要信息 const brief = bucket.briefs.get(girlId); if (brief) { return brief.getGrilCategory(); } } // 未找到 return 0; } /** --------------------------------------------------------- 技师的详细数据 --------------------------------------------------------- */ // 解析技师详细数据,一个 private parseOneGirlDetail( data: proto.cs.IGirlsDetail ): GirlDetailData | null { if (!data) return null; let oneData = new GirlDetailData(); oneData.init?.(DataId.GirlDetail); oneData.setData(data); return oneData; } /** 保存技师的详细数据 */ private setGirlDetail(categoryId: string, data: proto.cs.IGirlData[]): void { if (!data) return; const bucket = this.ensureBucket(categoryId); for (const g of data) { const one = this.parseOneGirlDetail(g.detail); if (!one) continue; bucket.details.set(g.id, one); } } /** 技师的详细信息是否存在 */ public isGirlDetailIn(categoryId: string, girlId: number): boolean { const b = this.ensureCategories().get(categoryId); if (!b) return false; return b.details.has(girlId); } /** 取某分类 + girlId 的详细数据 */ public getGrilDetail( categoryId: string, girlId: number ): GirlDetailData | null { const b = this.ensureCategories().get(categoryId); if (!b) return null; return b.details.get(girlId) ?? null; } /** 获取技师描述 */ public getGrilDesc(categoryId: string, girlId: number): string { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return ""; return oneData.getGirlDesc(); } /** 获取所有技师图片数据的数量 */ public getAllGrilPhotoDataCount(categoryId: string, girlId: number): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; return oneData.getAllGrilPhotoDataCount(); } /** 获取所有技师图片的id */ public getAllGrilPhotoId(categoryId: string, girlId: number): number[] { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return []; return oneData.getAllGrilPhotoId(); } /** 获取所有用来展示在列表的技师图片的id,可展示的有以下几种情况 * 1,图片类型为在详情页展示的(不管免费,付费,是否解锁) * 2,图片类型为在聊天触发的,并且已经达到了触发次数的(不管是否已经解锁) */ public getAllDisplayGrilPhotoId( categoryId: string, girlId: number ): number[] { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return []; // 所有id let allId = oneData.getAllGrilPhotoId(); // 总聊天次数 let chatTotalCount = this.getChatTotalCount(categoryId, girlId); // 用来展示的id let displayIds = []; for (let id of allId) { const unlockCounts = oneData.getGrilPhotoUnlockCounts(id); // 免费 const isFreeType = this.isGirlPhotoFreeType(categoryId, girlId, id); // 付费 const isPayType = this.isGirlPhotoPayType(categoryId, girlId, id); // 在详情页展示 const isShowInList = this.isGirlPhotoShowInList(categoryId, girlId, id); // 在聊天触发 const isShowInChat = this.isGirlPhotoShowInChat(categoryId, girlId, id); if (isShowInList) { displayIds.push(id); } else if (isShowInChat) { // 总聊天次数 大于等于 触发次数 if (chatTotalCount >= unlockCounts) { displayIds.push(id); } } } return displayIds; } /** 用来展示在列表的技师图片是否可见 */ public isGirlPhotoVisible( categoryId: string, girlId: number, id: number ): boolean { // 免费 const isFreeType = this.isGirlPhotoFreeType(categoryId, girlId, id); // 付费 const isPayType = this.isGirlPhotoPayType(categoryId, girlId, id); // 在详情页展示 const isShowInList = this.isGirlPhotoShowInList(categoryId, girlId, id); // 在聊天触发 const isShowInChat = this.isGirlPhotoShowInChat(categoryId, girlId, id); if (isShowInList) { if (isFreeType) { // 免费,可见 return true; } else if (isPayType) { // 付费,并且已经解锁,可见 const isUnlock = this.isImageUnlock(categoryId, girlId, id); if (isUnlock) return true; } } else if (isShowInChat) { // 总聊天次数 大于等于 触发次数 const isUnlock = this.isImageUnlock(categoryId, girlId, id); // 已经解锁,可见 if (isUnlock) return true; } // 其他情况,不可见 return false; } /** 获取 在聊天中,触发技师图片的id */ public getTriggerGrilPhotoId(categoryId: string, girlId: number): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; // 所有图片 id,展示类型属于在聊天中触发 let allId = oneData.getAllTriggerGrilPhotoId(); // 总聊天次数 let chatTotalCount = this.getChatTotalCount(categoryId, girlId); // 遍历 for (let id of allId) { let count = this.getGrilPhotoUnlockCounts(categoryId, girlId, id); if (chatTotalCount == count) return id; } return 0; } /** 获取第一个技师图片的资源路径 */ public getFirstGrilPhotoPath(categoryId: string, girlId: number): string { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return ""; // 第一个 id const ids = this.getAllGrilPhotoId(categoryId, girlId); const length = ids.length; if (length <= 0) return ""; // 返回数据 return oneData.getGrilPhotoPath(ids[0]); } /** 图片展示类型:在详情页展示 */ public isGirlPhotoShowInList( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return false; return oneData.isGirlPhotoShowInList(id); } /** 图片展示类型:在聊天触发 */ public isGirlPhotoShowInChat( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return false; return oneData.isGirlPhotoShowInChat(id); } /** 图片是否免费 */ public isGirlPhotoFreeType( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return false; // 价格 const price = oneData.getGrilPhotoPrice(id); return price <= 0; } /** 图片是否需要付费 */ public isGirlPhotoPayType( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return true; // 价格 const price = oneData.getGrilPhotoPrice(id); return price > 0; } /** 获取技师图片的类型 */ public getGrilPhotoType( categoryId: string, girlId: number, id: number ): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilPhotoType(id); } /** 获取技师图片的聊天触发次数 */ public getGrilPhotoUnlockCounts( categoryId: string, girlId: number, id: number ): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilPhotoUnlockCounts(id); } /** 获取技师图片的原来价格,除100 */ public getGrilPhotoOriginalPrice( categoryId: string, girlId: number, id: number ): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; let price = oneData.getGrilPhotoPrice(id); return price / 100; } /** 获取技师图片的价格 */ public getGrilPhotoPrice( categoryId: string, girlId: number, id: number ): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilPhotoPrice(id); } /** 获取技师图片的资源路径 */ public getGrilPhotoPic( categoryId: string, girlId: number, id: number ): string { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return ""; return oneData.getGrilPhotoPath(id); } /** 获取所有技师视频数据的数量 */ public getAllGrilVideoDataCount(categoryId: string, girlId: number): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; return oneData.getAllGrilVideoDataCount(); } /** 获取所有技师视频的id */ public getAllGrilVideoId(categoryId: string, girlId: number): number[] { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return []; return oneData.getAllGrilVideoId(); } /** 获取所有用来展示在列表的技师视频的id */ public getAllDisplayGrilVideoId( categoryId: string, girlId: number ): number[] { return this.getAllGrilVideoId(categoryId, girlId); } /** 用来展示在列表的技师视频是否可见 */ public isGirlVideoVisible( categoryId: string, girlId: number, id: number ): boolean { // 免费 const isFreeType = this.isGirlVideoFreeType(categoryId, girlId, id); // 付费 const isPayType = this.isGirlVideoPayType(categoryId, girlId, id); if (isFreeType) { // 免费,可见 return true; } else if (isPayType) { // 付费,并且已经解锁,可见 const isUnlock = this.isVideoUnlock(categoryId, girlId, id); if (isUnlock) return true; } // 其他情况,不可见 return false; } /** 视频是否免费 */ public isGirlVideoFreeType( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return false; // 价格 const price = oneData.getGrilVideoPrice(id); return price <= 0; } /** 视频是否需要付费 */ public isGirlVideoPayType( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return true; // 价格 const price = oneData.getGrilVideoPrice(id); return price > 0; } /** 获取第一个技师视频的资源路径 */ public getFirstGrilVideoPath(categoryId: string, girlId: number): string { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return ""; // 第一个 id const ids = this.getAllGrilVideoId(categoryId, girlId); const length = ids.length; if (length <= 0) return ""; // 返回数据 return oneData.getGrilVideoPath(ids[0]); } /** 获取技师视频的资源路径 */ public getGrilVideoPath( categoryId: string, girlId: number, id: number ): string { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return ""; return oneData.getGrilVideoPath(id); } /** 获取技师视频的关联情绪 */ public getGrilVideoEmotion( categoryId: string, girlId: number, id: number ): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilVideoEmotion(id); } /** 获取技师视频的原来价格,除100 */ public getGrilVideoOriginalPrice( categoryId: string, girlId: number, id: number ): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; let price = oneData.getGrilVideoPrice(id); return price / 100; } /** 获取技师视频的价格 */ public getGrilVideoPrice( categoryId: string, girlId: number, id: number ): number { let oneData = this.getGrilDetail(categoryId, girlId); if (!oneData) return 0; return oneData.getGrilVideoPrice(id); } /** --------------------------------------------------------- 技师的解锁数据 --------------------------------------------------------- */ // 创建一个技师解锁数据 private createOneGirlUnlock( id: number, isRelease: boolean, unlockTime: number, unlockedImageIds: number[], unlockedVideoIds: number[] ): GirlUnlockData { let oneData = new GirlUnlockData(); oneData.init?.(DataId.GirlUnlock); oneData.setId(id); oneData.setIsRelease(isRelease); oneData.setUnlockTime(unlockTime); if (unlockedImageIds) { oneData.setUnlockedImageIds(unlockedImageIds); } if (unlockedVideoIds) { oneData.setUnlockedVideoIds(unlockedVideoIds); } return oneData; } // 解析技师解锁数据,一个 private parseOneGirlUnlock(data: proto.cs.IGirlData): GirlUnlockData | null { if (!data) return null; let unlockedImageIds = []; if (data.images) { for (let one of data.images) { unlockedImageIds.push(one.resId); } } let unlockedVideoIds = []; if (data.videos) { for (let one of data.videos) { unlockedVideoIds.push(one.resId); } } let oneData = this.createOneGirlUnlock( data.id, data.isRelease, Number(data.unlockTime), unlockedImageIds, unlockedVideoIds ); return oneData; } /** 保存技师的解锁数据 */ private setGirlUnlock(categoryId: string, data: proto.cs.IGirlData[]): void { if (!data) return; const bucket = this.ensureBucket(categoryId); for (const g of data) { const one = this.parseOneGirlUnlock(g); if (!one) continue; bucket.unlocks.set(g.id, one); } } /** 刷新技师的解锁数据 */ private refreshGirlUnlock(data: proto.cs.ILastChatData): void { if (!data) return; let briefData = data.girl; let categoryId = briefData.category; let girlId = briefData.id; let unlockData = this.getGrilUnlock(categoryId.toString(), girlId); if (unlockData) { // 已存在数据,刷新 unlockData.setIsRelease(data.isRelease); unlockData.setUnlockTime(Number(data.unlockTime)); } else { // 不存在数据,创建 const bucket = this.ensureBucket(categoryId.toString()); let oneData = this.createOneGirlUnlock( data.id, data.isRelease, Number(data.unlockTime), [], [] ); if (oneData) { bucket.unlocks.set(data.id, oneData); } } } /** 取某分类 + girlId 的解锁数据 */ private getGrilUnlock( categoryId: string, girlId: number ): GirlUnlockData | null { const b = this.ensureCategories().get(categoryId); if (!b) return null; return b.unlocks.get(girlId) ?? null; } /** 技师的解锁数据是否存在 */ public isGirlUnlockIn(categoryId: string, girlId: number): boolean { const b = this.ensureCategories().get(categoryId); if (!b) return false; return b.unlocks.has(girlId); } /** 获取 付费技师是否已经解锁 */ public getIsRelease(categoryId: string, girlId: number): boolean { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return false; return oneData.getIsRelease(); } /** 保存 付费技师是否已经解锁 */ public setIsRelease( categoryId: string, girlId: number, value: boolean ): void { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return; oneData.setIsRelease(value); } /** 获取 角色解锁时间,时间戳,秒 */ public getUnlockTime(categoryId: string, girlId: number): number { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return 0; return oneData.getUnlockTime(); } /** 保存 角色解锁时间,时间戳,秒 */ public setUnlockTime( categoryId: string, girlId: number, value: number ): void { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return; oneData.setUnlockTime(value); } /** 判断图片是否解锁 */ public isImageUnlock( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return false; return oneData.isImageUnlock(id); } /** 解锁图片 */ public unlockImage(categoryId: string, girlId: number, id: number): void { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return; return oneData.unlockImage(id); } /** 获取所有解锁图片的 id */ public getUnlockedImageIds(categoryId: string, girlId: number): number[] { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return []; return oneData.getUnlockedImageIds(); } /** 判断视频是否解锁 */ public isVideoUnlock( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return false; return oneData.isVideoUnlock(id); } /** 解锁视频 */ public unlockVideo(categoryId: string, girlId: number, id: number): void { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return; return oneData.unlockVideo(id); } /** 获取所有解锁视频的 id */ public getUnlockedVideoIds(categoryId: string, girlId: number): number[] { let oneData = this.getGrilUnlock(categoryId, girlId); if (!oneData) return []; return oneData.getUnlockedVideoIds(); } /** 获取所有已经解锁技师的 id,不区分技师的付费类型 */ public getAllReleaseGirlIds(): number[] { const result: number[] = []; const seen = new Set(); // 用来去重 const cats = this.ensureCategories(); // 遍历 for (const [categoryId, bucket] of cats.entries()) { for (const girlId of bucket.girlIds) { if (this.getIsRelease(categoryId, girlId) && !seen.has(girlId)) { seen.add(girlId); // 标记已加入 result.push(girlId); } } } // 返回结果 return result; } /** --------------------------------------------------------- 技师的聊天数据 --------------------------------------------------------- */ // 创建一个技师聊天数据 private createOneGirlChat( id: number, chatTotalCount: number, chatRemainCount: number ): GirlChatData { let oneData = new GirlChatData(); oneData.init?.(DataId.GirlChat); oneData.setId(id); oneData.setChatTotalCount(chatTotalCount); oneData.setChatRemainCount(chatRemainCount); return oneData; } // 解析技师聊天数据,一个 private parseOneGirlChat(data: proto.cs.IGirlData): GirlChatData | null { if (!data) return null; let oneData = this.createOneGirlChat( data.id, data.chatTotalCount, data.chatRemainCount ); return oneData; } /** 保存技师的聊天数据 */ private setGirlChat(categoryId: string, data: proto.cs.IGirlData[]): void { if (!data) return; const bucket = this.ensureBucket(categoryId); for (const g of data) { const one = this.parseOneGirlChat(g); if (!one) continue; bucket.chats.set(g.id, one); } } /** 刷新技师的聊天数据 */ private refreshGirlChat(data: proto.cs.ILastChatData): void { if (!data) return; let briefData = data.girl; let categoryId = briefData.category; let girlId = briefData.id; let chatData = this.getGrilChat(categoryId.toString(), girlId); if (chatData) { // 已存在数据,刷新 chatData.setChatTotalCount(data.chatTotalCount); chatData.setChatRemainCount(data.chatRemainCount); chatData.setChatRecord(data.msgs); } else { // 不存在数据,创建 const bucket = this.ensureBucket(categoryId.toString()); let oneData = this.createOneGirlChat( data.id, data.chatTotalCount, data.chatRemainCount ); if (oneData) { oneData.setChatRecord(data.msgs); bucket.chats.set(data.id, oneData); } } } /** 取某分类 + girlId 的聊天数据 */ private getGrilChat(categoryId: string, girlId: number): GirlChatData | null { const b = this.ensureCategories().get(categoryId); if (!b) return null; return b.chats.get(girlId) ?? null; } /** 技师的聊天数据是否存在 */ public isGirlChatIn(categoryId: string, girlId: number): boolean { const b = this.ensureCategories().get(categoryId); if (!b) return false; return b.chats.has(girlId); } /** 获取总聊天次数 */ public getChatTotalCount(categoryId: string, girlId: number): number { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return 0; return oneData.getChatTotalCount(); } /** 保存总聊天次数 */ public setChatTotalCount( categoryId: string, girlId: number, value: number ): void { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return; return oneData.setChatTotalCount(value); } /** 获取剩余聊天次数 */ public getChatRemainCount(categoryId: string, girlId: number): number { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return 0; return oneData.getChatRemainCount(); } /** 保存剩余聊天次数 */ public setChatRemainCount( categoryId: string, girlId: number, value: number ): void { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return; return oneData.setChatRemainCount(value); } /** 更新剩余聊天次数 */ public useChat(categoryId: string, girlId: number, times: number = 1): void { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return; return oneData.useChat(times); } /** 是否可聊天 */ public isCanChat(categoryId: string, girlId: number): boolean { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return false; return oneData.isCanChat(); } /** 保存聊天记录 */ public setChatRecord( categoryId: string, girlId: number, data: proto.cs.IChatMsg[] ): void { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return; oneData.setChatRecord(data); } /** 获取聊天记录的所有 id */ public getChatRecordIds(categoryId: string, girlId: number): number[] { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return []; return oneData.getChatRecordIds(); } /** 获取最新的聊天记录的id */ public getLatestChatRecordId( categoryId: string, girlId: number ): number | null { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return null; return oneData.getLatestChatRecordId(); } /** 获取最新的聊天记录的时间戳(毫秒) */ public getLatestChatRecordTimestamp( categoryId: string, girlId: number ): number | null { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return null; return oneData.getLatestChatRecordTimestamp(); } /** 获取聊天记录,根据 id,是否是 ai 聊天数据 */ public getChatRecordIsAi( categoryId: string, girlId: number, id: number ): boolean { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return false; return oneData.getChatRecordIsAi(id); } /** 获取聊天记录,根据 id,聊天内容 */ public getChatRecordMsg( categoryId: string, girlId: number, id: number ): string { let oneData = this.getGrilChat(categoryId, girlId); if (!oneData) return ""; return oneData.getChatRecordMsg(id); } /** 获取所有可聊天的技师 id */ public getAllCanChatGirlIds(): number[] { const result: number[] = []; const seen = new Set(); // 用来去重 const cats = this.ensureCategories(); // 遍历 for (const [categoryId, bucket] of cats.entries()) { for (const girlId of bucket.girlIds) { if (this.isCanChat(categoryId, girlId) && !seen.has(girlId)) { seen.add(girlId); // 标记已加入 result.push(girlId); } } } // 排序 // 1,都存在聊天记录,按照聊天时间从近到远,否则,有聊天记录的排在前面 // 2,都没有聊天记录 // 2.1,付费类型角色排在前面,免费类型角色排在后面 // 2.2,如果角色都是付费类型,则角色id越大,排在前面 // 2.3,如果角色都是免费类型,则角色id越大,排在前面 result.sort((a, b) => { const categoryIdA = this.getGrilCategoryById(a); const categoryIdB = this.getGrilCategoryById(b); // 先取最新聊天时间戳 const tsA = this.getLatestChatRecordTimestamp(categoryIdA.toString(), a); const tsB = this.getLatestChatRecordTimestamp(categoryIdB.toString(), b); if (tsA && tsB) { // 都有聊天记录,按时间倒序 return tsB - tsA; } else if (tsA && !tsB) { // a 有聊天记录,优先 return -1; } else if (!tsA && tsB) { // b 有聊天记录,优先 return 1; } else { // 都没有聊天记录 → 解锁排前,最后是免费类型 const isPayTypeA = this.isGirlPayType(categoryIdA.toString(), a); const isFreeTypeA = this.isGirlFreeType(categoryIdA.toString(), a); const isPayTypeB = this.isGirlPayType(categoryIdB.toString(), b); const isFreeTypeB = this.isGirlFreeType(categoryIdB.toString(), b); if (isPayTypeA && isFreeTypeB) { // A 付费,B 免费 → A 前 return -1; } else if (isFreeTypeA && isPayTypeB) { // B 付费,A 免费 → B 前 return 1; } else { // 都是付费 or 都是免费 → 按 id 倒序 return b - a; } } }); // 返回结果 return result; } /** --------------------------------------------------------- 技师的好感度数据 --------------------------------------------------------- */ // 创建一个技师好感度数据 private createOneGirlFavorability(id: number, star: number, bookmarkTime: number): GirlFavorabilityData { let oneData = new GirlFavorabilityData(); oneData.init?.(DataId.GirlFavorability); oneData.setId(id); oneData.setStar(star); oneData.setBookmarkTime(bookmarkTime); return oneData; } // 解析技师好感度数据,一个 private parseOneGirlFavorability(data: proto.cs.IGirlData): GirlFavorabilityData | null { if (!data) return null; let oneData = this.createOneGirlFavorability(data.id, data.star, Number(data.bookmarkTime)); return oneData; } /** 保存技师的好感度数据 */ private setGirlFavorability(categoryId: string,data: proto.cs.IGirlData[]): void { if (!data) return; const bucket = this.ensureBucket(categoryId); for (const g of data) { const one = this.parseOneGirlFavorability(g); if (!one) continue; bucket.favorability.set(g.id, one); } } /** 刷新技师的好感度数据 */ private refreshGirlFavorability(data: proto.cs.ILastChatData): void { if (!data) return; let briefData = data.girl; let categoryId = briefData.category; let girlId = briefData.id; let favData = this.getGirlFavorability(categoryId.toString(), girlId); if (favData) { // 已存在数据,刷新 favData.setStar(data.star); } else { // 不存在数据,创建 const bucket = this.ensureBucket(categoryId.toString()); let oneData = this.createOneGirlFavorability(data.id, data.star, 0); if (oneData) { bucket.favorability.set(data.id, oneData); } } } /** 取某分类 + girlId 的好感度数据 */ private getGirlFavorability(categoryId: string, girlId: number): GirlFavorabilityData | null { const b = this.ensureCategories().get(categoryId); if (!b) return null; return b.favorability.get(girlId) ?? null; } /** 技师的好感度数据是否存在 */ public isGirlFavorabilityIn(categoryId: string, girlId: number): boolean { const b = this.ensureCategories().get(categoryId); if (!b) return false; return b.favorability.has(girlId); } /** 获取星级 */ public getStar(categoryId: string, girlId: number): number { let oneData = this.getGirlFavorability(categoryId, girlId); if (!oneData) return 0; return oneData.getStar(); } /** 获取收藏时间,时间戳,秒 */ public getBookmarkTime(categoryId: string, girlId: number): number { let oneData = this.getGirlFavorability(categoryId, girlId); if (!oneData) return 0; return oneData.getBookmarkTime(); } /** 保存 收藏时间,时间戳,秒 */ public setBookmarkTime(categoryId: string, girlId: number, value: number): void { let oneData = this.getGirlFavorability(categoryId, girlId); if (!oneData) return; oneData.setBookmarkTime(value); } /** 是否已经收藏 */ public isBookmarkGirl(categoryId: string, girlId: number): boolean { let oneData = this.getGirlFavorability(categoryId, girlId); if (!oneData) return false; return oneData.isBookmarkGirl(); } /** 获取所有已经收藏技师的 id */ public getAllBookmarkGirlIds(): number[] { const result: number[] = []; const seen = new Set(); // 用来去重 const cats = this.ensureCategories(); // 遍历 for (const [categoryId, bucket] of cats.entries()) { for (const girlId of bucket.girlIds) { if (this.isBookmarkGirl(categoryId, girlId) && !seen.has(girlId)) { seen.add(girlId); // 标记已加入 result.push(girlId); } } } // 返回结果 return result; } /** --------------------------------------------------------- 技师的其他数据 --------------------------------------------------------- */ // 创建一个技师其他数据 private createOneGirlOther(heatValue: number): GirlOtherData { let oneData = new GirlOtherData(); oneData.init?.(DataId.GirlOther); oneData.setHeatValue(heatValue); return oneData; } // 解析技师其他数据,一个 private parseOneGirlOther(data: proto.cs.IGirlData): GirlOtherData | null { if (!data) return null; let oneData = this.createOneGirlOther(Number(data.score)); return oneData; } /** 保存技师的其他数据 */ private setGirlOther(categoryId: string, data: proto.cs.IGirlData[]): void { if (!data) return; const bucket = this.ensureBucket(categoryId); for (const g of data) { const one = this.parseOneGirlOther(g); if (!one) continue; bucket.other.set(g.id, one); } } /** 取某分类 + girlId 的其他数据 */ private getGirlOther(categoryId: string, girlId: number): GirlOtherData | null { const b = this.ensureCategories().get(categoryId); if (!b) return null; return b.other.get(girlId) ?? null; } /** 技师的其他数据是否存在 */ public isGirlOtherIn(categoryId: string, girlId: number): boolean { const b = this.ensureCategories().get(categoryId); if (!b) return false; return b.other.has(girlId); } /** 获取热度值 */ public getHeatValue(categoryId: string, girlId: number): number { let oneData = this.getGirlOther(categoryId, girlId); if (!oneData) return 0; return oneData.getHeatValue(); } }