Files
test/Assets/Scripts/CECUIManager.cs
T
NguyenVanDat cc04ace9e1 Merge branch 'develop' into feature/clear-embedded-chip
# Conflicts:
#	Assets/PerfectWorld/Scripts/UI/Dialogs/DlgInstall.cs
2026-02-23 15:05:51 +07:00

514 lines
16 KiB
C#

using BrewMonster;
using BrewMonster.Network;
using BrewMonster.UI;
using CSNetwork;
using System;
using System.Collections.Generic;
using BrewMonster.Scripts.Managers;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.UIElements;
using TMPro;
public class CECUIManager : MonoSingleton<CECUIManager>
{
[SerializeField] private TMP_Text _fpsText;
[SerializeField] private List<GameObject> uiPrefabs; // drag các prefab UI vào đây
private readonly Dictionary<System.Type, GameObject> _spawnedUIs = new();
[SerializeField] private HUDNPC npsUI;
[SerializeField] private int currentTargetNPCID;
CECGameUIMan gameUI;
AUIManager aUIManager;
[SerializeField] private DialogScriptTableObject dialogResouce;
[SerializeField] private Canvas canvasDlg;
[SerializeField] private UnityEngine.UI.Button btnSecondClick;
[SerializeField] CDlgQuickBar m_pDlgQuickBar1;
public CDlgSkillSubOther m_pDlgSkillSubOther;
CDlgMessageBox m_pDlgMessageBox;
public CDlgSkillAction m_pDlgSkillAction;
Sprite[] m_iconlistIvtr;
private CDlgInfoTooltip m_pDlgSkillTooltip;
protected override void Awake()
{
base.Awake();
EventBus.Subscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
EventBus.Subscribe<NPCDiedEvent>(TryHideUINPC);
EventBus.Subscribe<MessageBoxEvent>(OnMessageBox);
gameUI = new CECGameUIMan();
gameUI.SetDependency(dialogResouce, canvasDlg);
gameUI.Init();
m_pDlgSkillAction = GetComponent<CDlgSkillAction>();
// Wire up second-click button / 连接第二次点击按钮
if (btnSecondClick != null)
{
btnSecondClick.onClick.AddListener(OnSecondClickButtonClicked);
}
ShowUI("Win_Hpmpxp");
}
private void Update()
{
// _fpsText.text = $"{Mathf.RoundToInt(1f / Time.deltaTime)}";
if (m_pDlgQuickBar1 != null)
{ m_pDlgQuickBar1.UpdateShortcuts(); }
}
private void OnDestroy()
{
EventBus.Unsubscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
EventBus.Unsubscribe<NPCDiedEvent>(TryHideUINPC);
EventBus.Unsubscribe<MessageBoxEvent>(OnMessageBox);
}
private void ShowUINPC(CECHostPlayer.NPCINFO obj)
{
npsUI.gameObject.SetActive(true);
npsUI.SetText($"{obj.CurrentHealth}/{obj.MaxHealth}", obj.Name, "");
npsUI.SetHealthImage((float)obj.CurrentHealth / (float)obj.MaxHealth);
currentTargetNPCID = obj.IDNPC;
}
public CDlgQuickBar GetCDlgQuickBar()
{
return m_pDlgQuickBar1;
}
private void TryHideUINPC(NPCDiedEvent obj)
{
if (obj.NPCID != currentTargetNPCID) return;
npsUI.gameObject.SetActive(false);
}
/// <summary>
/// Show UI by name of component ("DlgTask", "EC_InventoryUI")
/// </summary>
/// <param name="componentName">name of component ("DlgTask", "EC_InventoryUI")</param>
public void ShowUI(string componentName)
{
if (string.IsNullOrEmpty(componentName) || canvasDlg == null)
{
if (canvasDlg == null) Debug.LogError("canvasDlg chưa được gán");
return;
}
GetInGameUIMan().GetDialog(componentName).Show(true);
return;
var type = FindTypeByName(componentName);
if (TryShowCachedUI(type)) return;
if (FindUIByName(componentName, type)) return;
if (FindUIByType(type)) return;
Debug.LogWarning($"Không tìm thấy UI {componentName} đã spawn trong canvasDlg. Type found: {(type != null ? type.FullName : "null")}");
}
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();
/* if (m_pDlgSkillEdit != null && m_pDlgSkillEdit->IsShow())
{
// ¼¼Äܱ༭½çÃæÖ»ÔÚ Show(true) µÄʱºò²ÅÄܸüÐÂ
m_pDlgSkillEdit->Show(false);
}*/
}
/// <summary>
/// Show skill tooltip with description near the clicked skill button.
/// </summary>
/// <param name="hintText">The skill description and requirements</param>
/// <param name="sourceButton">The button RectTransform to position near</param>
public void ShowSkillTooltip(string hintText, RectTransform sourceButton)
{
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);
}
}
/// <summary>
/// Hide the skill tooltip if it's currently visible.
/// </summary>
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))
{
}
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());
dlgInstall.Show(false);
pHost.EndNPCService();
// m_pCurNPCEssence = NULL;
// m_pDlgInventory->Show(false);
pHost.GetPack((int)InventoryType.IVTRTYPE_PACK).UnfreezeAllItems();
ShowMessageBox(new MessageBoxData()
{
Message = pDlg.GetStringFromTable(228)
});
}
}
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;
}
/// <summary>
/// Ẩn UI (disable thay vì destroy)
/// </summary>
public void HideUI<T>() where T : Component
{
var type = typeof(T);
if (_spawnedUIs.TryGetValue(type, out var uiGo))
{
uiGo.SetActive(false);
}
}
/// <summary>
/// Kiểm tra UI có đang active không
/// </summary>
public bool IsUIActive<T>() where T : Component
{
var type = typeof(T);
return _spawnedUIs.TryGetValue(type, out var uiGo) && uiGo.activeSelf;
}
/// <summary>
/// Ẩn tất cả UI hiện tại
/// </summary>
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.Init();
}
return gameUI;
}
/// <summary>
/// Get the current target NPC ID (same as stored from NPCINFO event)
/// </summary>
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 = Resources.LoadAll<Sprite>("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();
}
}
/// <summary>
/// Handle second-click button click - triggers attack or move to NPC / 处理第二次点击按钮 - 触发攻击或移动到NPC
/// Uses OnMsgLBtnClick with selected target to reuse existing logic / 使用OnMsgLBtnClick和选中的目标来重用现有逻辑
/// </summary>
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)
{
if (string.IsNullOrEmpty(str))
return;
string strLwr = str.ToLower();
char[] chars = str.ToCharArray();
foreach (string bad in gameUI.m_vecBadWords)
{
int pos = 0;
string badLwr = bad.ToLower();
while ((pos = strLwr.IndexOf(badLwr, pos, StringComparison.Ordinal)) >= 0)
{
for (int j = 0; j < badLwr.Length; j++)
{
chars[pos + j] = '*';
}
pos += badLwr.Length;
}
}
str = new string(chars);
}
}