using BrewMonster; using BrewMonster.Managers; using BrewMonster.Network; using BrewMonster.UI; using System; using System.Collections.Generic; using BrewMonster.PerfectWorld.Scripts.Utility.ChatFilter; using BrewMonster.Scripts.Chat.EmotionData; using BrewMonster.Scripts.Managers; using BrewMonster.Scripts.Task.UI; using BrewMonster.Scripts.UI; using CSNetwork.GPDataType; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using TMPro; public class CECUIManager : MonoSingleton { [SerializeField] private TMP_Text _fpsText; [SerializeField] private List uiPrefabs; // drag các prefab UI vào đây private readonly Dictionary _spawnedUIs = new(); /// Stack of dialog names (front = index 0 = top / currently on top). [SerializeField]private List _uiStack = new(); /// Max number of dialogs in stack; when exceeded on Push, the top is popped once. 0 = unlimited. [SerializeField] private int _maxStack = 1; [SerializeField] private HUDNPC npsUI; [SerializeField] private int currentTargetNPCID; CECGameUIMan gameUI; public CECGameUIMan GameUI => gameUI; AUIManager aUIManager; AUIDialog _dlgPlayerOptions; [SerializeField] private DialogScriptTableObject dialogResouce; [SerializeField] private Canvas canvasDlg; public Transform DialogCanvasTransform => canvasDlg != null ? canvasDlg.transform : null; [SerializeField] [Tooltip("Chat TMP: EmotionLibrarySpriteMap (SO). CECGameUIMan is not a MonoBehaviour — assign here on CECUIManager.")] private EmotionLibrarySpriteMap _emotionLibrarySpriteMap; [SerializeField] private UnityEngine.UI.Button btnSecondClick; [SerializeField] CDlgQuickBar m_pDlgQuickBar1; [SerializeField] GameObject ChangeSkillShortcutButton; public CDlgSkillSubOther m_pDlgSkillSubOther; CDlgMessageBox m_pDlgMessageBox; public CDlgSkillAction m_pDlgSkillAction; Sprite[] m_iconlistIvtr; private CDlgInfoTooltip m_pDlgSkillTooltip; // Task update timer / 任务更新计时器 private float _nextTaskUpdateTime = 0f; private const float TASK_UPDATE_INTERVAL = .1f; protected override void Awake() { base.Awake(); EventBus.Subscribe(ShowUINPC); EventBus.Subscribe(OnTargetHUDClear); EventBus.Subscribe(OnHostPlayerLevelUpUI); EventBus.Subscribe(TryHideUINPC); EventBus.Subscribe(OnMessageBox); gameUI = new CECGameUIMan(); gameUI.SetDependency(dialogResouce, canvasDlg); gameUI.SetEmotionSpriteMap(_emotionLibrarySpriteMap); gameUI.Init(); m_pDlgSkillAction = GetComponent(); // Wire up second-click button / 连接第二次点击按钮 if (btnSecondClick != null) { btnSecondClick.onClick.AddListener(OnSecondClickButtonClicked); } ShowUI("Win_Hpmpxp"); #if UNITY_EDITOR if(ChangeSkillShortcutButton == null) { return; } ChangeSkillShortcutButton.SetActive(true); #else if(ChangeSkillShortcutButton == null) { return; } ChangeSkillShortcutButton.SetActive(false); #endif } private void Update() { // _fpsText.text = $"{Mathf.RoundToInt(1f / Time.deltaTime)}"; if (m_pDlgQuickBar1 != null) { m_pDlgQuickBar1.UpdateShortcuts(); } // Task UI must run from this Update(): TickInvoker often never calls CECUIManager.Tick in practice // (registration order, DDOL instance, or no TickInvoker in scene), so logs/body there never ran. // 任务 UI 必须在此 Update 驱动:TickInvoker 在部分场景下根本不会调到本类 Tick。 if (Time.unscaledTime < _nextTaskUpdateTime) return; _nextTaskUpdateTime = Time.unscaledTime + TASK_UPDATE_INTERVAL; UpdateTaskUI(); if (EC_Game.GetGameRun()?.GetHostPlayer() != null) EC_Game.GetGameRun()?.ShowAccountLoginInfo(); } /// /// Rebuild acceptable-quest cache after host levels up (heavy scan; not on player code path). /// 升级后重建可接任务缓存(全表扫描放在 UI 层)。 /// private void OnHostPlayerLevelUpUI(CECHostPlayer.HostPlayerLevelUpUIEvent _) { DlgTask.RebuildAcceptableQuestCache(); } /// /// Update task UI from DlgTask and DlgTaskTrace / 从DlgTask和DlgTaskTrace更新任务UI /// private void UpdateTaskUI() { try { var inGameUIMan = GetInGameUIMan(); if (inGameUIMan == null) return; // Prefer cached DlgTask from Init (Win_Quest). Do not rely on `is DlgTask` on AUIDialog: // prefab may register as AUIDialog while DlgTask is the concrete component on the same GO. // 优先使用 Init 里缓存的 DlgTask;字典里可能是 AUIDialog 引用,`is DlgTask` 会为 false。 DlgTask dlgTask = null; if (inGameUIMan is CECGameUIMan gameUi && gameUi.GetDlgTask() != null) dlgTask = gameUi.GetDlgTask(); if (dlgTask == null) { var dlg = inGameUIMan.GetDialog(CECUIHelper.DlgTaskName); dlgTask = dlg != null ? dlg.GetComponent() : null; } if (dlgTask == null) return; if (EC_Game.GetGameRun()?.GetHostPlayer() == null) return; var bShowTrace = inGameUIMan.IsDialogShow("Win_QuestMinion"); dlgTask.RefreshTaskTrace(bShowTrace); dlgTask.Tick(); } catch (System.Exception) { // Silently handle errors to avoid spamming logs / 静默处理错误以避免日志刷屏 // Task UI update errors are handled silently / 任务UI更新错误被静默处理 } } private void OnDestroy() { EventBus.Unsubscribe(ShowUINPC); EventBus.Unsubscribe(OnTargetHUDClear); EventBus.Unsubscribe(OnHostPlayerLevelUpUI); EventBus.Unsubscribe(TryHideUINPC); EventBus.Unsubscribe(OnMessageBox); } private void ShowUINPC(CECHostPlayer.NPCINFO obj) { var host = EC_Game.GetGameRun()?.GetHostPlayer(); if (host != null && host.GetSelectedTarget() != obj.IDNPC) return; npsUI.gameObject.SetActive(true); string hpText = obj.MaxHealth > 0 ? $"{obj.CurrentHealth}/{obj.MaxHealth}" : "-/-"; npsUI.SetText(hpText, obj.Name ?? "", ""); float fill = obj.MaxHealth > 0 ? (float)obj.CurrentHealth / (float)obj.MaxHealth : 1f; npsUI.SetHealthImage(fill); currentTargetNPCID = obj.IDNPC; // Render ElsePlayer portrait avatar — mirrors C++ PlayerRenderPortrait / SetRenderCallback if (GPDataTypeHelper.ISPLAYERID(obj.IDNPC)) { var elsePlayer = EC_ManMessageMono.Instance?.GetECManPlayer? .GetPlayer(obj.IDNPC) as EC_ElsePlayer; if (elsePlayer != null) { ElsePlayerPortraitCapture.Instance?.SetTarget(elsePlayer.transform); npsUI.SetAvatar(ElsePlayerPortraitCapture.Instance?.OutputTexture); return; } } // NPC thường hoặc không tìm thấy ElsePlayer — ẩn avatar ElsePlayerPortraitCapture.Instance?.ClearTarget(); npsUI.ShowAvatar(false); } private void OnTargetHUDClear(CECHostPlayer.TargetHUDClearEvent _) { ElsePlayerPortraitCapture.Instance?.ClearTarget(); npsUI.ShowAvatar(false); npsUI.gameObject.SetActive(false); } public CDlgQuickBar GetCDlgQuickBar() { return m_pDlgQuickBar1; } private void TryHideUINPC(NPCDiedEvent obj) { if (obj.NPCID != currentTargetNPCID) return; ElsePlayerPortraitCapture.Instance?.ClearTarget(); npsUI.ShowAvatar(false); npsUI.gameObject.SetActive(false); } /// /// Show UI by name of component ("DlgTask", "EC_InventoryUI"). When isStack is true, pushes the dialog onto the UI stack (brings to front and tracks for Pop). /// /// Name of component ("DlgTask", "EC_InventoryUI") /// If true, push onto stack (show + SetAsLastSibling + track); if false, just show. /// just hide current ui- not pop public AUIDialog ShowUI(string componentName) { if (string.IsNullOrEmpty(componentName) || canvasDlg == null) { if (canvasDlg == null) Debug.LogError("canvasDlg is null"); return null; } var currentDialogue = GetCurrentDialog(); if (currentDialogue != null) { if (_uiStack.Count > 0 && string.Compare(_uiStack[0], componentName, StringComparison.Ordinal) == 0) { return currentDialogue; } currentDialogue.Show(false); } return Push(componentName); } /// /// Show a modal on top without hiding stack dialogs (e.g. DlgQuantity over storage + inventory). /// public AUIDialog ShowDialogOverlay(string componentName) { if (string.IsNullOrEmpty(componentName) || canvasDlg == null) return null; var dlg = GetInGameUIMan()?.GetDialog(componentName); if (dlg == null) return null; dlg.Show(true); dlg.transform.SetAsLastSibling(); EC_UIUtility.BringPanelToFront(dlg.gameObject); return dlg; } public void HideDialogOverlay(string componentName) { if (string.IsNullOrEmpty(componentName)) return; var dlg = GetInGameUIMan()?.GetDialog(componentName); if (dlg != null) dlg.Show(false); } public void HideCurrentUIInStack() { Pop(); //show next one var currentDialogue = GetCurrentDialog(); if (currentDialogue != null) { currentDialogue.Show(true); } } /// /// Push a dialog onto the UI stack: show it, add to front of stack, and SetAsLastSibling so it draws on top. If already in stack, moves it to front. /// private AUIDialog Push(string componentName) { if (string.IsNullOrEmpty(componentName) || canvasDlg == null) return null; _uiStack.Remove(componentName); if (_maxStack > 0 && _uiStack.Count >= _maxStack) Pop(); var dlg = GetInGameUIMan().GetDialog(componentName); if (dlg == null) return null; dlg.Show(true); _uiStack.Insert(0, componentName); dlg.transform.SetAsLastSibling(); return dlg; } /// /// Show warehouse + inventory together without hiding the first dialog (C++ PopupStorageDialog). /// public void ShowStorageDialogPair() { if (canvasDlg == null) return; var gui = GetInGameUIMan(); if (gui == null) return; var storageDlg = gui.GetDialog("EC_StorageUI"); var invDlg = gui.GetDialog("Win_Inventory"); if (storageDlg == null || invDlg == null) return; _uiStack.Remove("Win_Inventory"); _uiStack.Remove("EC_StorageUI"); invDlg.Show(true); storageDlg.Show(true); _uiStack.Insert(0, "Win_Inventory"); _uiStack.Insert(0, "EC_StorageUI"); // Inventory below, storage on top (detail panel uses EC_UIUtility overlay sort). invDlg.transform.SetAsLastSibling(); storageDlg.transform.SetAsLastSibling(); } /// Hide warehouse pair and restore previous stack top if any. public void HideStorageDialogPair() { _uiStack.Remove("EC_StorageUI"); _uiStack.Remove("Win_Inventory"); var gui = GetInGameUIMan(); gui?.GetDialog("Win_Inventory")?.Show(false); gui?.GetDialog("EC_StorageUI")?.Show(false); if (_uiStack.Count > 0) { var newTop = gui?.GetDialog(_uiStack[0]); if (newTop != null) { newTop.Show(true); newTop.transform.SetAsLastSibling(); } } } /// /// Pop the top dialog off the stack: hide it and bring the new top (if any) to front. Returns true if something was popped. /// private bool Pop() { if (_uiStack.Count == 0) return false; string top = _uiStack[0]; _uiStack.RemoveAt(0); var dlg = GetInGameUIMan().GetDialog(top); if (dlg != null) dlg.Show(false); if (_uiStack.Count > 0) { var newTop = GetInGameUIMan().GetDialog(_uiStack[0]); if (newTop != null) newTop.transform.SetAsLastSibling(); } return true; } /// Returns the name of the dialog currently on top of the stack, or null if stack is empty. public string GetCurrentUI() { if (_uiStack.Count == 0) return null; return _uiStack[0]; } /// Returns the dialog instance currently on top of the stack, or null if stack is empty. public AUIDialog GetCurrentDialog() { var currentUI = GetCurrentUI(); if (currentUI == null) return null; return GetInGameUIMan().GetDialog(currentUI); } /// Returns the number of dialogs in the stack (0 when empty). public int GetStackCount() => _uiStack.Count; /// Returns true if the given dialog name is in the stack. public bool IsInStack(string componentName) { return !string.IsNullOrEmpty(componentName) && _uiStack.Contains(componentName); } /// Returns the dialog name at the given index (0 = top) without removing. Returns null if index is out of range. public string PeekStack(int index = 0) { if (index < 0 || index >= _uiStack.Count) return null; return _uiStack[index]; } /// Clears the entire stack. If hideAll is true, hides every dialog in the stack before clearing. public void ClearStack(bool hideAll = true) { if (hideAll) { var gui = GetInGameUIMan(); foreach (string name in _uiStack) { var dlg = gui?.GetDialog(name); if (dlg != null) dlg.Show(false); } } _uiStack.Clear(); } public CDlgMessageBox ShowMessageBoxGeneral(string title, string message, AUIDialog dlg) { var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox; if (msgBox != null) { msgBox.ShowMessageBoxGeneral(title, message, dlg); return msgBox; } Debug.LogError("DlgMessageBox not found in InGameUIMan"); return null; } public CDlgMessageBox ShowMessageBoxYes(string title, string message, AUIDialog dlg, Action onClickedYes) { var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox; if (msgBox != null) { msgBox.ShowMessageBoxYes(title, message, dlg, onClickedYes); return msgBox; } Debug.LogError("DlgMessageBox not found in InGameUIMan"); return null; } public CDlgMessageBox ShowMessageBoxNo(string title, string message, AUIDialog dlg, Action onClickedNo) { var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox; if (msgBox != null) { msgBox.ShowMessageBoxNo(title, message, dlg, onClickedNo); return msgBox; } Debug.LogError("DlgMessageBox not found in InGameUIMan"); return null; } public CDlgMessageBox ShowMessageBoxYesAndNo(string title, string message, AUIDialog dlg, Action onClickedYes, Action onClickedNo) { var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox; if (msgBox != null) { msgBox.ShowMessageBoxYesAndNo(title, message, dlg,onClickedYes, onClickedNo); return msgBox; } Debug.LogError("DlgMessageBox not found in InGameUIMan"); return null; } /// /// Dialog names on that are normal gameplay HUD and must NOT block world raycasts /// (the stack always has at least Win_Hpmpxp after ). /// private static readonly HashSet HudStackDialogNames = new HashSet(StringComparer.Ordinal) { "Win_Hpmpxp", }; /// /// Returns true when a modal / non-HUD dialog is open and world clicks should be ignored. /// public bool IsWorldInteractionBlockedByUI() { if (_uiStack == null || _uiStack.Count == 0) return false; foreach (var name in _uiStack) { if (string.IsNullOrEmpty(name)) continue; if (!HudStackDialogNames.Contains(name)) return true; } return false; } /// /// True when the pointer hits UI that should consume the click (buttons, fields, scroll views). /// Unlike , full-screen Images/Text with raycast /// but no interactive control do not block — so clicks can reach the world for NPC selection. /// public static bool IsPointerOverInteractiveUI() { var es = EventSystem.current; if (es == null) return false; Vector2 pos = Input.mousePosition; if (Input.touchCount > 0) pos = Input.GetTouch(0).position; var ped = new PointerEventData(es) { position = pos }; var results = new List(); es.RaycastAll(ped, results); if (results.Count == 0) return false; foreach (var r in results) { var go = r.gameObject; if (go == null) continue; if (go.GetComponentInParent() != null) return true; if (go.GetComponentInParent() != null) return true; if (go.GetComponentInParent() != null) return true; if (go.GetComponentInParent() != null) return true; } return false; } // public CDlgMessageBox ShowMessageBox(MessageBoxData messageBoxData) // { // var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox; // if (msgBox != null) // { // msgBox.ShowMessageBox(messageBoxData); // return msgBox; // } // else // { // Debug.LogError("DlgMessageBox not found in InGameUIMan"); // } // // return null; // } // public CDlgMessageBox ShowMessageBox(string title, string message, MessageBoxType messageBoxType, // Action onClickedYes = null, Action onClickedNo = null) // { // var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox; // if (msgBox != null) // { // msgBox.ShowMessageBox(new MessageBoxData() // { // Title = title, // Message = message, // MessageBoxType = messageBoxType, // OnClickedYes = onClickedYes, // OnClickedNo = onClickedNo // }); // return msgBox; // } // else // { // Debug.LogError("DlgMessageBox not found in InGameUIMan"); // } // // return null; // } public void UpdateSkillRelatedUI() { // ¸üм¼ÄÜÏà¹ØµÄ½çÃæÏÔʾ if (m_pDlgQuickBar1) m_pDlgQuickBar1.UpdateShortcuts(); SkillTriggerPanel.Instance?.Refresh(); /* if (m_pDlgSkillEdit != null && m_pDlgSkillEdit->IsShow()) { // ¼¼Äܱ༭½çÃæÖ»ÔÚ Show(true) µÄʱºò²ÅÄܸüРm_pDlgSkillEdit->Show(false); }*/ } /// /// Show skill tooltip with description near the clicked skill button. /// /// The skill description and requirements /// The button RectTransform to position near public void ShowSkillTooltip(string hintText, RectTransform sourceButton, Action triggerAction = null) { if (string.IsNullOrEmpty(hintText)) { Debug.LogWarning("[CECUIManager] ShowSkillTooltip called with empty hint text"); return; } // Lazy-load the tooltip dialog if (m_pDlgSkillTooltip == null) { var tooltip = GetInGameUIMan().GetDialog("CDlgInfoTooltip") as CDlgInfoTooltip; if (tooltip != null) { m_pDlgSkillTooltip = tooltip; } else { Debug.LogWarning( "[CECUIManager] CDlgSkillTooltip not found in dialog resource. Tooltip will not be displayed."); return; } } if (m_pDlgSkillTooltip != null) { m_pDlgSkillTooltip.ShowTooltip(hintText, sourceButton, triggerAction); } } /// /// Hide the skill tooltip if it's currently visible. /// public void HideSkillTooltip() { if (m_pDlgSkillTooltip != null) { m_pDlgSkillTooltip.HideTooltip(); } } private void OnMessageBox(MessageBoxEvent messageBoxEvent) { BMLogger.LogError("CECUIManager OnMessageBox called"); int iRetVal = messageBoxEvent.iRetVal; AUIDialog pDlg = messageBoxEvent.pDlg; if (pDlg == m_pDlgMessageBox) { OnNewMessageBox(iRetVal); return; } UnityGameSession pSession = UnityGameSession.Instance; CECHostPlayer pHost = CECGameRun.Instance.GetHostPlayer(); if (string.Equals(pDlg.GetName(), "Game_Quit", StringComparison.OrdinalIgnoreCase)) { // TODO // Cancel hotkey customize because hot key state is determinted by CECHostInputFilter // which is shared between repick role // // if (m_pDlgSettingQuickKey->IsShow()) // m_pDlgSettingQuickKey->Show(false); if( pSession.GameSession.IsConnected ) { // TODO // if (CECCrossServer::Instance().IsOnSpecialServer()) // g_pGame->GetGameRun()->GetPendingLogOut().AppendForSaveConfig(new CECPendingLogoutCrossServer()); // else // g_pGame->GetGameRun()->GetPendingLogOut().AppendForSaveConfig(new CECPendingLogoutHalf()); EC_Game.GetGameRun().GetPendingLogOut().AppendForSaveConfig(new CECPendingLogoutHalf()); } else EC_Game.GetGameRun().SetLogoutFlag(2); } else if ((string.Equals(pDlg.GetName(), "Game_TeachSkill", StringComparison.OrdinalIgnoreCase) && DialogBoxCommandIDs.IDOK == iRetVal) || (string.Equals(pDlg.GetName(), "Game_LearnSkill", StringComparison.OrdinalIgnoreCase) && DialogBoxCommandIDs.IDOK == iRetVal)) { if (string.Equals(pDlg.GetName(), "Game_TeachSkill", StringComparison.OrdinalIgnoreCase)) { } else if (string.Equals(pDlg.GetName(), "Game_LearnSkill", StringComparison.OrdinalIgnoreCase)) { /* int skillID = (int)pDlg.GetData(); int nCondition = pHost.CheckSkillLearnCondition(skillID, true); if (0 == nCondition) { UnityGameSession.c2s_SendCmdNPCSevLearnSkill(skillID); }*/ /*else if (1 == nCondition) AddChatMessage(GetStringFromTable(270), GP_CHAT_MISC); else if (6 == nCondition) AddChatMessage(GetStringFromTable(527), GP_CHAT_MISC); else if (7 == nCondition) AddChatMessage(GetStringFromTable(541), GP_CHAT_MISC); else if (8 == nCondition) AddChatMessage(GetStringFromTable(271), GP_CHAT_MISC); else if (9 == nCondition) AddChatMessage(GetStringFromTable(556), GP_CHAT_MISC); else if (10 == nCondition) AddChatMessage(GetStringFromTable(557), GP_CHAT_MISC); else if (12 == nCondition) AddChatMessage(GetStringFromTable(11168), GP_CHAT_MISC);*/ } } //else if (pDlg is DlgInstall dlgInstall && dlgInstall.GetInstallMode == DlgInstall.InstallMode.Disenchase && // DialogBoxCommandIDs.IDOK == iRetVal) //{ // UnityGameSession.c2s_CmdNPCSevClearEmbeddedChip(dlgInstall.FirstSlotIndex, // dlgInstall.SelectedEquip.GetTemplateID()); // UnityGameSession.c2s_CmdGetAllData(true, true, false); // dlgInstall.Show(false); // pHost.EndNPCService(); // // m_pCurNPCEssence = NULL; // // m_pDlgInventory->Show(false); // pHost.GetPack((int)InventoryType.IVTRTYPE_PACK).UnfreezeAllItems(); // ShowMessageBoxGeneral("", pDlg.GetStringFromTable(228), null); //} } private bool OnNewMessageBox(int iRetVal) { return true; } // private System.Type FindTypeByName(string componentName) // { // string[] namespacePrefixes = { // "", // No namespace // "BrewMonster.Scripts.Task.UI.", // "BrewMonster.UI.", // "BrewMonster.Scripts.UI.", // "BrewMonster." // }; // // // Try with common namespace prefixes // foreach (var prefix in namespacePrefixes) // { // string fullTypeName = string.IsNullOrEmpty(prefix) ? componentName : prefix + componentName; // var type = System.Type.GetType(fullTypeName); // if (type != null) return type; // } // // // Search in all assemblies // foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies()) // { // var type = assembly.GetType(componentName); // if (type != null) return type; // // foreach (var prefix in namespacePrefixes) // { // if (string.IsNullOrEmpty(prefix)) continue; // type = assembly.GetType(prefix + componentName); // if (type != null) return type; // } // } // // return null; // } // // private bool TryShowCachedUI(System.Type type) // { // if (type != null && _spawnedUIs.TryGetValue(type, out var uiGo)) // { // uiGo.SetActive(true); // return true; // } // return false; // } // // private bool FindUIByName(string componentName, System.Type type) // { // for (int i = 0; i < canvasDlg.transform.childCount; i++) // { // var child = canvasDlg.transform.GetChild(i); // if (!child.name.Contains(componentName) && child.name != componentName) continue; // // if (type != null) // { // var foundComponent = child.GetComponentInChildren(type, true); // if (foundComponent != null) // { // ActivateAndCacheUI(foundComponent.gameObject, type); // return true; // } // } // // ActivateAndCacheUI(child.gameObject, type); // return true; // } // return false; // } // // private bool FindUIByType(System.Type type) // { // if (type == null) return false; // // var foundComponent = canvasDlg.GetComponentInChildren(type, true); // if (foundComponent != null) // { // ActivateAndCacheUI(foundComponent.gameObject, type); // return true; // } // return false; // } private void ActivateAndCacheUI(GameObject uiGameObject, System.Type type) { uiGameObject.SetActive(true); if (type != null) _spawnedUIs[type] = uiGameObject; } /// /// Ẩn UI (disable thay vì destroy) /// // public void HideUI() where T : Component // { // var type = typeof(T); // if (_spawnedUIs.TryGetValue(type, out var uiGo)) // { // uiGo.SetActive(false); // } // } /// /// Kiểm tra UI có đang active không /// public bool IsUIActive() where T : Component { var type = typeof(T); return _spawnedUIs.TryGetValue(type, out var uiGo) && uiGo.activeSelf; } /// /// Ẩn tất cả UI hiện tại /// public void HideAll() { foreach (var kv in _spawnedUIs) { kv.Value.SetActive(false); } } public CECGameUIMan GetInGameUIMan() { if (gameUI == null) { gameUI = new CECGameUIMan(); gameUI.SetDependency(dialogResouce, canvasDlg); gameUI.SetEmotionSpriteMap(_emotionLibrarySpriteMap); gameUI.Init(); } return gameUI; } public void GetIconStateMgr() { } /// Shows the player options menu for the given character. Requires a prefab with id "DlgPlayerOptions" in DialogScriptTableObject. public void ShowPlayerOptionsDialog(int characterId, Vector2 position) { if (characterId == 0 || canvasDlg == null) return; var gui = GetInGameUIMan(); if (_dlgPlayerOptions == null) _dlgPlayerOptions = gui.GetDialog("DlgPlayerOptions"); _dlgPlayerOptions?.ShowForPlayer(characterId); _dlgPlayerOptions.transform.position = position; } /// /// Opens Win_Award () and fills it from equipped template ids using local item data /// (). For debugging local prop/description behavior. /// /// The dialog instance, or null if the prefab is not registered. public void ShowDlgAwardEquippedItemsLocalTest() { const string dlgAwardName = "Win_Award"; CDlgAward award = null; if (GetInGameUIMan().GetDialog(dlgAwardName) is CDlgAward dlgAward) { award = dlgAward; } var shown = ShowUI(dlgAwardName) as CDlgAward; (shown ?? award).TestItemInInventory(); } /// /// Get the current target NPC ID (same as stored from NPCINFO event) /// public int GetCurrentTargetNPCID() { return currentTargetNPCID; } //todo: change this code to other place private int slot = 0; public Sprite[] IconlistIvtr { get { if (m_iconlistIvtr == null || m_iconlistIvtr.Length == 0) { m_iconlistIvtr = Resources.LoadAll("UI/IconSprites/iconlist_ivtrm_multisprite"); } return m_iconlistIvtr; } } public Sprite GetSpriteInListIvtr(string name) { foreach (var item in IconlistIvtr) { if (item.name.Equals(name)) { return item; } } return null; } public void OnClickedWaveHand() { // if (EC_Game.GetGameRun().GetPoseCmdShortcuts() == null) // { // EC_Game.GetGameRun().StartGame(0, Vector3.zero); // } CECShortcut pSC = EC_Game.GetGameRun().GetPoseCmdShortcuts().GetShortcut(slot); if (pSC != null) // && pObjSrc->GetDataPtr("ptr_CECShortcut") == pSC { // a_LogOutput(1, "[Dat Emote] ptr_CECShortcut"); pSC.Execute(); } } public void OnClickFly() { CECHostPlayer hostPlayer = EC_Game.GetGameRun()?.GetHostPlayer(); if (hostPlayer != null) { hostPlayer.CmdFly(true); } } public void OnChangeSkillShortcut() { #if UNITY_EDITOR CECHostPlayer hostPlayer = EC_Game.GetGameRun()?.GetHostPlayer(); if (hostPlayer != null) { hostPlayer.CycleSkillShortcuts(); } #endif } /// /// Handle second-click button click - triggers attack or move to NPC / 处理第二次点击按钮 - 触发攻击或移动到NPC /// Uses OnMsgLBtnClick with selected target to reuse existing logic / 使用OnMsgLBtnClick和选中的目标来重用现有逻辑 /// private void OnSecondClickButtonClicked() { CECHostPlayer hostPlayer = EC_Game.GetGameRun()?.GetHostPlayer(); if (hostPlayer != null) { int selectedTarget = hostPlayer.GetSelectedTarget(); if (selectedTarget != 0) { // Call OnMsgLBtnClick with the selected target to simulate second click / 使用选中的目标调用OnMsgLBtnClick以模拟第二次点击 hostPlayer.OnMsgLBtnClick(selectedTarget); } } } public struct MessageBoxEvent { public int iRetVal; public AUIDialog pDlg; public MessageBoxEvent(int retVal, AUIDialog dlg) { iRetVal = retVal; pDlg = dlg; } } public void FilterBadWords(ref string str) { str = ChatFilterService.Filter(str, out var isValidWord); } }