Files
test/Assets/Scripts/CECUIManager.cs
T
2026-02-25 13:38:33 +07:00

577 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
AUIDialog _dlgPlayerOptions;
[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;
// Task update timer / 任务更新计时器
private float _nextTaskUpdateTime = 0f;
private const float TASK_UPDATE_INTERVAL = .1f;
protected override void Awake()
{
base.Awake();
EventBus.Subscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
EventBus.Subscribe<CECHostPlayer.TargetHUDClearEvent>(OnTargetHUDClear);
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(); }
// Periodically update task UI (DlgTask and DlgTaskTrace) / 定期更新任务UIDlgTask和DlgTaskTrace
if (Time.unscaledTime >= _nextTaskUpdateTime)
{
_nextTaskUpdateTime = Time.unscaledTime + TASK_UPDATE_INTERVAL;
UpdateTaskUI();
}
}
/// <summary>
/// Update task UI from DlgTask and DlgTaskTrace / 从DlgTask和DlgTaskTrace更新任务UI
/// </summary>
private void UpdateTaskUI()
{
try
{
var inGameUIMan = GetInGameUIMan();
if (inGameUIMan == null) return;
var dlgTaskDialog = inGameUIMan.GetDialog("Win_Quest");
var dlgTaskTraceDialog = inGameUIMan.GetDialog("Win_QuestMinion");
if (dlgTaskDialog != null && dlgTaskDialog is BrewMonster.Scripts.Task.UI.DlgTask dlgTaskForTrace)
{
if (dlgTaskTraceDialog != null && dlgTaskTraceDialog.IsShow())
{
dlgTaskForTrace.RefreshTaskTrace();
}
dlgTaskForTrace.Tick();
}
}
catch (System.Exception)
{
// Silently handle errors to avoid spamming logs / 静默处理错误以避免日志刷屏
// Task UI update errors are handled silently / 任务UI更新错误被静默处理
}
}
private void OnDestroy()
{
EventBus.Unsubscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
EventBus.Unsubscribe<CECHostPlayer.TargetHUDClearEvent>(OnTargetHUDClear);
EventBus.Unsubscribe<NPCDiedEvent>(TryHideUINPC);
EventBus.Unsubscribe<MessageBoxEvent>(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;
}
private void OnTargetHUDClear(CECHostPlayer.TargetHUDClearEvent _)
{
npsUI.gameObject.SetActive(false);
}
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>Shows the player options menu for the given character. Requires a prefab with id "DlgPlayerOptions" in DialogScriptTableObject.</summary>
public void ShowPlayerOptionsDialog(int characterId)
{
if (characterId == 0 || canvasDlg == null) return;
var gui = GetInGameUIMan();
if (_dlgPlayerOptions == null)
_dlgPlayerOptions = gui.GetDialog("DlgPlayerOptions");
_dlgPlayerOptions?.ShowForPlayer(characterId);
}
/// <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);
}
}