2025-08-12 15:01:59 +08:00
|
|
|
import {
|
|
|
|
|
_decorator,
|
|
|
|
|
Component,
|
|
|
|
|
EditBox,
|
|
|
|
|
Node,
|
|
|
|
|
Label,
|
|
|
|
|
Sprite,
|
|
|
|
|
UITransform,
|
2025-08-26 19:41:13 +08:00
|
|
|
VideoPlayer,
|
2025-09-11 00:03:22 +08:00
|
|
|
Size,
|
2025-09-11 18:49:27 +08:00
|
|
|
Vec3,
|
2025-08-12 15:01:59 +08:00
|
|
|
} from "cc";
|
2025-08-11 16:08:59 +08:00
|
|
|
// 首先加载 polyfills 以确保兼容性
|
|
|
|
|
import "../../utils/polyfills";
|
|
|
|
|
import { DialogManager } from "../../manager/DialogManager";
|
2025-08-26 19:41:13 +08:00
|
|
|
import { ChatController, IChatPanelCallback } from "../../core/ChatController";
|
2025-07-25 18:27:30 +08:00
|
|
|
import li_BaseView from "db://assets/Scripts/Main/Common/li_BaseView";
|
|
|
|
|
import Utils from "db://assets/Scripts/Main/Common/Utils";
|
2025-08-12 15:01:59 +08:00
|
|
|
import { InnerMsgCode } from "db://assets/Scripts/Main/Config/InnerMsgCode";
|
|
|
|
|
import { ChatContentsLayout } from "../components/ChatContentsLayout";
|
|
|
|
|
import { ViewManager } from "db://assets/Scripts/Main/Manager/ViewManager";
|
2025-07-25 18:27:30 +08:00
|
|
|
import GameRootUI from "db://assets/Scripts/Main/Common/GameRootUI";
|
2025-08-12 15:01:59 +08:00
|
|
|
import { ImagePopup } from "../components/ImagePopup";
|
2025-08-12 16:58:02 +08:00
|
|
|
|
2025-08-01 18:28:36 +08:00
|
|
|
import ResManager from "db://assets/Scripts/Main/Manager/ResManager";
|
2025-08-12 19:49:50 +08:00
|
|
|
import LanguageUtils from "../../../Main/Common/LanguageUtils";
|
2025-08-25 20:15:42 +08:00
|
|
|
import { UITransitionHelper } from "../../utils/UITransitionHelper";
|
2025-09-15 16:11:15 +08:00
|
|
|
import { PriceType, VideoEmotion, purchase } from "../../../schema/schema";
|
2025-08-27 16:12:19 +08:00
|
|
|
import { PayToTalkSubpanel } from "./PayToTalkSubpanel";
|
2025-09-10 16:43:46 +08:00
|
|
|
import { DataId, DataManager } from "../../data/DataManager";
|
|
|
|
|
import { GirlData } from "../../data/GirlData";
|
2025-09-11 00:03:22 +08:00
|
|
|
import { SceneBgVideoLayer } from "../../../Sub/UI/SceneBgVideoLayer";
|
2025-09-12 18:20:41 +08:00
|
|
|
import { NavigationManager, PanelType } from "../../manager/NavigationManager";
|
2025-09-15 16:11:15 +08:00
|
|
|
import { GirlService } from "../../network/services/GirlService";
|
|
|
|
|
import proto from "db://assets/Scripts/proto/proto.pb.js";
|
2025-09-16 16:55:39 +08:00
|
|
|
import { TipsPanel } from "./TipsPanel";
|
2025-07-22 16:43:10 +08:00
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
|
|
|
|
@ccclass("ChatPanel")
|
2025-08-26 19:41:13 +08:00
|
|
|
export class ChatPanel extends li_BaseView implements IChatPanelCallback {
|
2025-08-11 16:08:59 +08:00
|
|
|
manager: DialogManager = null;
|
2025-08-27 16:12:19 +08:00
|
|
|
private chatController: ChatController = null;
|
|
|
|
|
|
|
|
|
|
@property(PayToTalkSubpanel)
|
|
|
|
|
payToTalkPanel: PayToTalkSubpanel = null;
|
2025-07-22 16:43:10 +08:00
|
|
|
|
|
|
|
|
@property(EditBox)
|
|
|
|
|
editBox: EditBox = null;
|
|
|
|
|
|
2025-07-25 15:20:02 +08:00
|
|
|
@property(Label)
|
|
|
|
|
girlName: Label = null;
|
|
|
|
|
|
2025-09-10 15:48:27 +08:00
|
|
|
// @property(Sprite)
|
|
|
|
|
// girlImg: Sprite = null;
|
2025-08-01 18:28:36 +08:00
|
|
|
|
2025-09-11 00:03:22 +08:00
|
|
|
// 移除直接的 VideoPlayer 引用,改用 SceneBgVideoLayer 单例
|
|
|
|
|
// @property(VideoPlayer)
|
|
|
|
|
// girlVideo: VideoPlayer = null;
|
|
|
|
|
@property(UITransform)
|
|
|
|
|
videoArea: UITransform = null;
|
|
|
|
|
|
|
|
|
|
/** 获取 SceneBgVideoLayer 单例实例 */
|
|
|
|
|
private get videoLayer(): SceneBgVideoLayer | null {
|
|
|
|
|
return SceneBgVideoLayer.handle;
|
|
|
|
|
}
|
2025-08-26 19:41:13 +08:00
|
|
|
|
2025-07-25 18:27:30 +08:00
|
|
|
@property(ChatContentsLayout)
|
|
|
|
|
layout: ChatContentsLayout = null;
|
|
|
|
|
|
|
|
|
|
@property(ImagePopup)
|
|
|
|
|
popUpImage: ImagePopup = null;
|
|
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
categoryId: string;
|
2025-08-12 15:01:59 +08:00
|
|
|
id: number;
|
2025-08-01 18:28:36 +08:00
|
|
|
private _nodeTab: any = {};
|
|
|
|
|
|
2025-08-12 19:49:50 +08:00
|
|
|
nameKey: string;
|
2025-08-26 19:41:13 +08:00
|
|
|
private currentEmotion: VideoEmotion | null = null;
|
2025-08-13 16:53:27 +08:00
|
|
|
|
2025-08-13 11:31:21 +08:00
|
|
|
private onLanguageChangeCallback = () => {
|
|
|
|
|
if (!this.girlName) return;
|
|
|
|
|
this.girlName.string = LanguageUtils.getText(this.nameKey);
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-12 18:20:41 +08:00
|
|
|
targetSize;
|
|
|
|
|
videoAreaPos;
|
|
|
|
|
onLoadCT() {
|
|
|
|
|
Utils.parseNode(this.node, this._nodeTab);
|
|
|
|
|
|
|
|
|
|
// 获取 videoArea 的尺寸和位置
|
|
|
|
|
this.targetSize = this.videoArea.contentSize;
|
|
|
|
|
this.videoAreaPos = new Vec3(540, 1170, 0);
|
|
|
|
|
|
|
|
|
|
this.register();
|
|
|
|
|
//this.refresh();
|
|
|
|
|
this.payToTalkPanel.node.active = false;
|
|
|
|
|
|
|
|
|
|
// 检查 SceneBgVideoLayer 是否可用
|
|
|
|
|
if (!this.videoLayer) {
|
|
|
|
|
console.error("ChatPanel: SceneBgVideoLayer.handle 未初始化");
|
|
|
|
|
} else {
|
|
|
|
|
console.log("ChatPanel: 成功获取 SceneBgVideoLayer 实例");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
register() {
|
|
|
|
|
Utils.addInnerEL(
|
|
|
|
|
InnerMsgCode.LanguageChange,
|
|
|
|
|
this,
|
|
|
|
|
this.onLanguageChangeCallback
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Utils.addInnerEL(
|
|
|
|
|
InnerMsgCode.Chat_EmotionInitialized,
|
|
|
|
|
this,
|
|
|
|
|
this.onEmotionInitialized
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Utils.addInnerEL(
|
|
|
|
|
InnerMsgCode.ChatTotalCountChange,
|
|
|
|
|
this,
|
|
|
|
|
this.onChatCountChange
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onDestroy(): void {
|
|
|
|
|
Utils.removeInnerEL(
|
|
|
|
|
InnerMsgCode.LanguageChange,
|
|
|
|
|
this,
|
|
|
|
|
this.onLanguageChangeCallback
|
|
|
|
|
);
|
|
|
|
|
Utils.removeInnerEL(
|
|
|
|
|
InnerMsgCode.ChatTotalCountChange,
|
|
|
|
|
this,
|
|
|
|
|
this.onChatCountChange
|
|
|
|
|
);
|
|
|
|
|
Utils.removeInnerEL(
|
|
|
|
|
InnerMsgCode.Chat_EmotionInitialized,
|
|
|
|
|
this,
|
|
|
|
|
this.onEmotionInitialized
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 解绑ChatController(不销毁,因为它是单例)
|
|
|
|
|
if (this.chatController) {
|
|
|
|
|
this.chatController.unbindView();
|
|
|
|
|
this.chatController = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-15 16:11:15 +08:00
|
|
|
async refresh() {
|
2025-09-12 18:20:41 +08:00
|
|
|
const newRoleId = NavigationManager.Instance.getSelectedGirlId();
|
2025-09-15 16:11:15 +08:00
|
|
|
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
2025-08-26 19:41:13 +08:00
|
|
|
|
2025-08-27 16:12:19 +08:00
|
|
|
// 检查是否是切换角色
|
|
|
|
|
const isRoleSwitch = this.id && this.id !== newRoleId;
|
|
|
|
|
|
|
|
|
|
this.id = newRoleId;
|
2025-09-12 18:20:41 +08:00
|
|
|
this.categoryId =
|
2025-09-15 16:11:15 +08:00
|
|
|
NavigationManager.Instance.getSelectedCategoryId().toString();
|
|
|
|
|
|
|
|
|
|
const isFree =
|
|
|
|
|
girlData.getGrilPriceType(this.categoryId.toString(), this.id) ==
|
|
|
|
|
PriceType.free;
|
|
|
|
|
const isRelease = girlData.getIsRelease(
|
|
|
|
|
this.categoryId.toString(),
|
|
|
|
|
this.id
|
|
|
|
|
);
|
|
|
|
|
if (!isFree && !isRelease) {
|
|
|
|
|
//未解锁
|
|
|
|
|
ViewManager.I.openBundlesPopupView("GirlListPopupPanel", {
|
|
|
|
|
base: this,
|
|
|
|
|
category: this.categoryId,
|
|
|
|
|
id: this.id,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-08-26 19:41:13 +08:00
|
|
|
|
2025-08-27 16:12:19 +08:00
|
|
|
// 获取ChatController单例并绑定当前Panel
|
|
|
|
|
this.chatController = ChatController.Instance;
|
|
|
|
|
this.chatController.bindView(this);
|
|
|
|
|
|
|
|
|
|
// 初始化或切换ChatController
|
2025-08-25 20:15:42 +08:00
|
|
|
if (this.id && this.id > 0) {
|
2025-09-10 16:43:46 +08:00
|
|
|
if (
|
|
|
|
|
isRoleSwitch &&
|
|
|
|
|
this.chatController.hasRoleData(this.categoryId, this.id)
|
|
|
|
|
) {
|
2025-08-27 16:12:19 +08:00
|
|
|
// 如果是角色切换且有缓存数据,使用switchRole
|
|
|
|
|
console.log(
|
|
|
|
|
`ChatPanel: Switching from role ${this.chatController.getCurrentRoleId()} to role ${
|
|
|
|
|
this.id
|
|
|
|
|
}`
|
|
|
|
|
);
|
2025-09-10 16:43:46 +08:00
|
|
|
this.chatController.switchRole(this.categoryId, this.id);
|
2025-08-27 16:12:19 +08:00
|
|
|
} else {
|
|
|
|
|
// 首次初始化或没有缓存数据,使用initialize
|
|
|
|
|
console.log(`ChatPanel: Initializing role ${this.id}`);
|
2025-09-10 16:43:46 +08:00
|
|
|
this.chatController.initialize(this.categoryId, this.id);
|
2025-08-27 16:12:19 +08:00
|
|
|
}
|
2025-08-25 20:15:42 +08:00
|
|
|
}
|
2025-08-01 18:28:36 +08:00
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
this.nameKey = girlData.getGrilName(this.categoryId, this.id);
|
2025-09-15 16:11:15 +08:00
|
|
|
if (this.nameKey == "") {
|
|
|
|
|
const reqData = {
|
|
|
|
|
id: this.id,
|
|
|
|
|
};
|
|
|
|
|
let res = await GirlService.I.reqGetGirlDetail(reqData);
|
|
|
|
|
if (res && res.code === proto.cs.EnmRetCode.SUCCESS) {
|
|
|
|
|
// 保存数据
|
|
|
|
|
girlData.setGirlDetailData(this.categoryId.toString(), res.data);
|
|
|
|
|
this.nameKey = girlData.getGrilName(this.categoryId, this.id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
this.girlName.string = LanguageUtils.getText(this.nameKey);
|
2025-08-12 15:01:59 +08:00
|
|
|
|
2025-08-27 16:12:19 +08:00
|
|
|
// 通过ChatController获取商业视频数据
|
|
|
|
|
const chatModel = this.chatController.getChatModel();
|
|
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
// Load initial video based on current emotion
|
2025-09-11 00:03:22 +08:00
|
|
|
if (this.videoLayer) {
|
2025-09-10 16:43:46 +08:00
|
|
|
// Get current emotion from ChatController
|
|
|
|
|
const currentEmotion = this.chatController.getCurrentEmotion();
|
2025-08-27 16:12:19 +08:00
|
|
|
console.log(
|
2025-09-10 16:43:46 +08:00
|
|
|
`Current emotion for role ${this.id}: ${VideoEmotion[currentEmotion]}`
|
2025-08-27 16:12:19 +08:00
|
|
|
);
|
|
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
// Get appropriate video from ChatModel
|
|
|
|
|
const initialVideo =
|
|
|
|
|
chatModel.getVideoByEmotion(currentEmotion) ||
|
|
|
|
|
chatModel.getDefaultVideo();
|
|
|
|
|
|
|
|
|
|
if (initialVideo) {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.log(
|
2025-09-10 16:43:46 +08:00
|
|
|
`Loading initial video: ${initialVideo} (emotion: ${VideoEmotion[initialVideo]})`
|
2025-08-26 19:41:13 +08:00
|
|
|
);
|
2025-08-27 16:12:19 +08:00
|
|
|
|
2025-09-10 16:43:46 +08:00
|
|
|
// Set current emotion to the loaded video's emotion
|
|
|
|
|
this.currentEmotion = this.chatController.getCurrentEmotion();
|
2025-09-11 10:54:06 +08:00
|
|
|
|
2025-09-11 18:49:27 +08:00
|
|
|
// 使用新的统一 playVideo 方法,现在它会自动处理缩放和位置
|
|
|
|
|
|
2025-09-11 10:54:06 +08:00
|
|
|
this.videoLayer.playVideo(initialVideo, {
|
|
|
|
|
loop: true,
|
2025-09-11 18:49:27 +08:00
|
|
|
size: this.targetSize,
|
|
|
|
|
position: this.videoAreaPos,
|
2025-09-11 10:54:06 +08:00
|
|
|
});
|
2025-09-11 00:03:22 +08:00
|
|
|
|
2025-09-11 18:49:27 +08:00
|
|
|
// 注意:移除了 adjustVideoScale() 调用,因为 playVideo 现在会自动处理缩放和位置
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this.currentEmotion = null; // Reset current emotion when no videos available
|
2025-09-11 00:03:22 +08:00
|
|
|
console.log("No SceneBgVideoLayer available for role", this.id);
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
2025-07-25 15:20:02 +08:00
|
|
|
}
|
2025-08-26 19:41:13 +08:00
|
|
|
|
2025-09-11 18:49:27 +08:00
|
|
|
/**
|
|
|
|
|
* @deprecated 此方法已废弃,现在由 SceneBgVideoLayer.playVideo() 自动处理缩放和位置
|
|
|
|
|
* 保留此方法仅为了兼容性,但不再主动调用
|
|
|
|
|
*/
|
2025-08-26 19:41:13 +08:00
|
|
|
adjustVideoScale() {
|
2025-09-11 18:49:27 +08:00
|
|
|
console.log(
|
|
|
|
|
"ChatPanel: adjustVideoScale() 方法已废弃,缩放和位置由 playVideo() 自动处理"
|
|
|
|
|
);
|
|
|
|
|
// 如果确实需要手动调整,可以重新调用 playVideo
|
|
|
|
|
// this.videoLayer.playVideo(currentVideo, { size, position });
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
2025-09-10 21:49:39 +08:00
|
|
|
onChatCountChange() {
|
|
|
|
|
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
|
|
|
|
|
let triggerId = girlData.getTriggerGrilPhotoId(this.categoryId, this.id);
|
|
|
|
|
|
2025-09-11 00:03:22 +08:00
|
|
|
if (triggerId == 0) return;
|
2025-09-10 21:49:39 +08:00
|
|
|
|
|
|
|
|
this.popUpImage.refresh(this.categoryId, this.id, triggerId);
|
|
|
|
|
}
|
2025-08-26 19:41:13 +08:00
|
|
|
|
|
|
|
|
setVideoEnable(enable: boolean) {
|
2025-09-11 00:03:22 +08:00
|
|
|
if (!this.videoLayer) {
|
|
|
|
|
console.error("ChatPanel: SceneBgVideoLayer 不可用");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-08-26 19:41:13 +08:00
|
|
|
|
|
|
|
|
if (enable) {
|
2025-09-11 00:03:22 +08:00
|
|
|
this.videoLayer.resume();
|
|
|
|
|
console.log("ChatPanel: 恢复视频播放");
|
|
|
|
|
} else {
|
|
|
|
|
this.videoLayer.pause();
|
|
|
|
|
console.log("ChatPanel: 暂停视频播放");
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private switchVideoByEmotion(emotion: VideoEmotion): void {
|
2025-09-11 00:03:22 +08:00
|
|
|
if (!this.videoLayer) {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.warn("Cannot switch video: missing video player");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Get video data from ChatModel through ChatController
|
|
|
|
|
const chatModel = this.chatController.getChatModel();
|
2025-08-26 19:41:13 +08:00
|
|
|
|
|
|
|
|
// Check if emotion has changed
|
|
|
|
|
if (this.currentEmotion === emotion) {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.log(
|
|
|
|
|
`Emotion ${VideoEmotion[emotion]} unchanged, skipping video switch`
|
|
|
|
|
);
|
2025-08-26 19:41:13 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 16:12:19 +08:00
|
|
|
// Get video matching the emotion from ChatModel
|
|
|
|
|
const matchingVideo = chatModel.getVideoByEmotion(emotion);
|
|
|
|
|
|
2025-08-26 19:41:13 +08:00
|
|
|
if (matchingVideo) {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.log(
|
2025-09-10 16:43:46 +08:00
|
|
|
`Switching to video for emotion ${
|
|
|
|
|
VideoEmotion[emotion]
|
|
|
|
|
}: ${matchingVideo} (from ${
|
2025-08-27 16:12:19 +08:00
|
|
|
this.currentEmotion !== null
|
|
|
|
|
? VideoEmotion[this.currentEmotion]
|
|
|
|
|
: "null"
|
|
|
|
|
})`
|
|
|
|
|
);
|
|
|
|
|
|
2025-09-11 10:54:06 +08:00
|
|
|
this.videoLayer.playVideo(matchingVideo, {
|
|
|
|
|
loop: true,
|
2025-09-11 18:49:27 +08:00
|
|
|
size: this.targetSize,
|
|
|
|
|
position: this.videoAreaPos, // 修复:使用正确的位置而不是 Vec3.ZERO
|
2025-09-11 10:54:06 +08:00
|
|
|
});
|
2025-08-27 16:12:19 +08:00
|
|
|
|
2025-08-26 19:41:13 +08:00
|
|
|
// Update current emotion state
|
|
|
|
|
this.currentEmotion = emotion;
|
2025-08-27 16:12:19 +08:00
|
|
|
|
2025-09-11 18:49:27 +08:00
|
|
|
// 注意:移除了 adjustVideoScale() 调用,因为 playVideo 现在会自动处理缩放和位置
|
2025-08-26 19:41:13 +08:00
|
|
|
this.setVideoEnable(true);
|
|
|
|
|
} else {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.warn(
|
|
|
|
|
`No video found for emotion ${VideoEmotion[emotion]}, falling back to default video`
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Fallback to default video from ChatModel
|
|
|
|
|
const fallbackVideo = chatModel.getDefaultVideo();
|
|
|
|
|
if (fallbackVideo) {
|
|
|
|
|
console.log(
|
2025-09-10 16:43:46 +08:00
|
|
|
`Loading fallback video: ${fallbackVideo} (emotion: ${VideoEmotion[fallbackVideo]})`
|
2025-08-27 16:12:19 +08:00
|
|
|
);
|
|
|
|
|
|
2025-09-11 10:54:06 +08:00
|
|
|
this.videoLayer.playVideo(fallbackVideo, {
|
|
|
|
|
loop: true,
|
2025-09-11 18:49:27 +08:00
|
|
|
size: this.targetSize,
|
|
|
|
|
position: this.videoAreaPos,
|
2025-09-11 10:54:06 +08:00
|
|
|
});
|
2025-08-27 16:12:19 +08:00
|
|
|
|
2025-08-26 19:41:13 +08:00
|
|
|
// Update current emotion state to the fallback video's emotion
|
2025-09-10 16:43:46 +08:00
|
|
|
this.currentEmotion = this.chatController.getCurrentEmotion();
|
2025-09-11 18:49:27 +08:00
|
|
|
|
|
|
|
|
// 注意:移除了 adjustVideoScale() 调用,因为 playVideo 现在会自动处理缩放和位置
|
2025-08-26 19:41:13 +08:00
|
|
|
this.setVideoEnable(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 16:12:19 +08:00
|
|
|
private onEmotionInitialized(data: {
|
|
|
|
|
roleId: number;
|
|
|
|
|
emotion: VideoEmotion;
|
|
|
|
|
}): void {
|
2025-08-26 19:41:13 +08:00
|
|
|
// 检查是否是当前角色
|
|
|
|
|
if (data.roleId === this.id) {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.log(
|
|
|
|
|
`Emotion initialized for current role ${this.id}: ${
|
|
|
|
|
VideoEmotion[data.emotion]
|
|
|
|
|
}`
|
|
|
|
|
);
|
|
|
|
|
|
2025-08-26 19:41:13 +08:00
|
|
|
// 切换到对应的视频
|
|
|
|
|
this.switchVideoByEmotion(data.emotion);
|
|
|
|
|
} else {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.log(
|
|
|
|
|
`Emotion initialized for role ${data.roleId} (not current role ${this.id}), ignoring`
|
|
|
|
|
);
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-16 19:03:00 +08:00
|
|
|
onDialogUpdate(isPlayer: boolean) {
|
2025-08-13 12:55:27 +08:00
|
|
|
if (this.layout) {
|
2025-09-16 19:03:00 +08:00
|
|
|
if (isPlayer) {
|
|
|
|
|
this.layout.updatePlayerDialog(
|
|
|
|
|
DialogManager.getInstance().GetPlayerDialog()
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
this.layout.updateAIDialogs(DialogManager.getInstance().GetAIDialog());
|
|
|
|
|
}
|
2025-08-13 12:55:27 +08:00
|
|
|
}
|
2025-07-25 18:27:30 +08:00
|
|
|
}
|
2025-07-22 16:43:10 +08:00
|
|
|
protected onEnable(): void {
|
2025-08-11 16:08:59 +08:00
|
|
|
if (!this.manager) this.manager = DialogManager.getInstance();
|
2025-09-12 18:20:41 +08:00
|
|
|
|
|
|
|
|
this.refresh();
|
2025-07-22 16:43:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async OnClickSend() {
|
|
|
|
|
const str = this.editBox.string;
|
2025-09-16 16:55:39 +08:00
|
|
|
if (!str || str == "") {
|
|
|
|
|
TipsPanel.show("请输入内容");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-07-22 16:43:10 +08:00
|
|
|
|
2025-08-26 19:41:13 +08:00
|
|
|
// 通过ChatController发送消息
|
2025-08-27 16:12:19 +08:00
|
|
|
const succeed = await this.chatController.sendMessage(str);
|
|
|
|
|
if (succeed)
|
|
|
|
|
// 清空输入框
|
|
|
|
|
this.editBox.string = "";
|
2025-07-25 18:27:30 +08:00
|
|
|
}
|
|
|
|
|
|
2025-08-26 19:41:13 +08:00
|
|
|
// === IChatPanelCallback 接口实现 ===
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 消息发送开始回调
|
|
|
|
|
* @param message 用户发送的消息
|
|
|
|
|
*/
|
|
|
|
|
public onMessageSent(message: string): void {
|
|
|
|
|
console.log("Message sent:", message);
|
2025-08-27 16:12:19 +08:00
|
|
|
// 消息发送后开始显示加载动画,由DialogManager处理
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 接收到AI回复回调
|
|
|
|
|
* @param response AI的回复内容
|
|
|
|
|
*/
|
|
|
|
|
public onMessageReceived(response: string): void {
|
|
|
|
|
console.log("Message received:", response);
|
2025-08-27 16:12:19 +08:00
|
|
|
// AI回复收到后加载动画会被自动移除,可以在这里添加其他UI效果
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 对话更新回调
|
|
|
|
|
*/
|
2025-09-16 19:03:00 +08:00
|
|
|
public onDialogUpdated(isPlayer: boolean): void {
|
2025-08-26 19:41:13 +08:00
|
|
|
// 更新对话显示
|
2025-09-16 19:03:00 +08:00
|
|
|
this.onDialogUpdate(isPlayer);
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 错误处理回调
|
|
|
|
|
* @param error 错误信息
|
|
|
|
|
*/
|
|
|
|
|
public onError(error: Error): void {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.error("Chat error:", error);
|
|
|
|
|
// 出错时加载动画会被自动移除,可以在这里显示错误提示给用户
|
|
|
|
|
}
|
2025-09-10 15:48:27 +08:00
|
|
|
|
2025-08-27 16:12:19 +08:00
|
|
|
onChatLimitReached(): void {
|
2025-09-10 21:49:39 +08:00
|
|
|
this.payToTalkPanel.show(this.categoryId, this.id);
|
2025-09-16 16:55:39 +08:00
|
|
|
TipsPanel.show(LanguageUtils.getText("chat_error_code_1001"));
|
2025-08-26 19:41:13 +08:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 情绪状态更新回调 (实现IChatPanelCallback接口)
|
|
|
|
|
* @param emotion 当前情绪状态
|
|
|
|
|
*/
|
|
|
|
|
public onEmotionUpdated(emotion: VideoEmotion): void {
|
2025-08-27 16:12:19 +08:00
|
|
|
console.log(
|
|
|
|
|
`ChatPanel: Emotion updated to ${VideoEmotion[emotion]} (${emotion})`
|
|
|
|
|
);
|
|
|
|
|
|
2025-08-26 19:41:13 +08:00
|
|
|
// Switch video based on the new emotion
|
|
|
|
|
this.switchVideoByEmotion(emotion);
|
2025-08-27 16:12:19 +08:00
|
|
|
|
2025-08-26 19:41:13 +08:00
|
|
|
// Additional UI updates can be added here based on emotion
|
|
|
|
|
// 例如:改变角色表情、背景色、播放相应的动画等
|
|
|
|
|
switch (emotion) {
|
|
|
|
|
case VideoEmotion.calm_down:
|
|
|
|
|
// 平静状态的UI更新
|
|
|
|
|
console.log("UI state: Calm");
|
|
|
|
|
break;
|
|
|
|
|
case VideoEmotion.arousal:
|
|
|
|
|
// 兴奋状态的UI更新
|
|
|
|
|
console.log("UI state: Arousal");
|
|
|
|
|
break;
|
|
|
|
|
case VideoEmotion.desire:
|
|
|
|
|
// 渴望状态的UI更新
|
|
|
|
|
console.log("UI state: Desire");
|
|
|
|
|
break;
|
|
|
|
|
case VideoEmotion.passion:
|
|
|
|
|
// 激情状态的UI更新
|
|
|
|
|
console.log("UI state: Passion");
|
|
|
|
|
break;
|
|
|
|
|
case VideoEmotion.orgasm:
|
|
|
|
|
// 高潮状态的UI更新
|
|
|
|
|
console.log("UI state: Orgasm");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-12 15:01:59 +08:00
|
|
|
returnBtn() {
|
2025-09-11 18:49:27 +08:00
|
|
|
// Navigate back to GirlDetailPanel with current girlId using smooth transition
|
2025-09-12 18:20:41 +08:00
|
|
|
NavigationManager.Instance.switchToPanel(PanelType.GIRL_DETAIL);
|
2025-07-22 16:43:10 +08:00
|
|
|
}
|
2025-08-13 16:53:27 +08:00
|
|
|
onClickRecord() {
|
|
|
|
|
ViewManager.I.openBundlesView("RecordPanel", this.id);
|
|
|
|
|
}
|
2025-08-27 16:12:19 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 手动清除指定角色的数据(调试用)
|
|
|
|
|
* @param roleId 角色ID,不传则清除当前角色
|
|
|
|
|
*/
|
|
|
|
|
public clearRoleDataDebug(roleId?: number): void {
|
|
|
|
|
if (!this.chatController) {
|
|
|
|
|
console.warn("ChatController not initialized");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const targetRoleId = roleId || this.id;
|
|
|
|
|
if (!targetRoleId) {
|
|
|
|
|
console.warn("No role ID specified");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.chatController.clearRoleData(targetRoleId);
|
|
|
|
|
console.log(`Cleared data for role ${targetRoleId}`);
|
|
|
|
|
}
|
2025-07-22 16:43:10 +08:00
|
|
|
}
|