using System; using System.Collections.Generic; using System.Linq; using BrewMonster; using BrewMonster.Scripts.Skills; using TMPro; using UnityEngine; using UnityEngine.UI; namespace BrewMonster.UI { [DisallowMultipleComponent] public class CDlgSkillSubList : AUIDialog { [Header("Templates")] [SerializeField] private AUISubDialog m_pSubRank; [SerializeField] private CDlgSkillSubListItem m_pSubSkill; [Header("Layout")] [SerializeField] private RectTransform m_contentRoot; [SerializeField] private RectTransform m_contentRootSkill; [SerializeField] private ScrollRect m_scrollRect; [SerializeField] private float m_windowScale = 1f; [SerializeField] private TMP_Text totalSPText; [Header("State")] [SerializeField] private bool m_isEvil; private readonly Dictionary m_rankSubDialogs = new(); private readonly List m_skillSubDialogs = new(); private readonly Dictionary m_skillSubDialogsMap = new(); private int m_skillSubCount; // 当前显示的技能数量 / Current shown skill count private float m_curBottom; // 当前底部位置 / Current bottom position private float m_skillHeight; // 技能子对话高度 / Skill sub dialog height private float m_rankHeight; // 阶位对话高度 / Rank dialog height private float m_originWidth; // 初始宽度 / Initial width private float m_originHeight; // 初始高度 / Initial height private float m_originBottom; // 初始底部位置 / Initial bottom position private bool m_bAllocRankDlgs; // 是否已创建阶位子对话 / Whether rank sub dialogs are allocated private int m_selectedSkillId; private void Awake() { if (m_contentRoot == null) { m_contentRoot = transform as RectTransform; } EventBus.Subscribe(OnModelChange); CacheTemplateInfo(); HideTemplates(); } public override void OnEnable() { base.OnEnable(); OnShowDialog(); } private void OnShowDialog() { InitRankDlgs(); ResetDialog(); // 保留原始隐藏新图标逻辑 / Keep original "hide new" logic (pending port) // GetGameUIMan()->m_pDlgSystem->ShowNewImg(false); // GetGameUIMan()->m_pDlgSystemb->ShowNewImg(false); // GetGameUIMan()->m_pDlgSystem5->ShowNewImg(false); // GetGameUIMan()->m_pDlgSystem5b->ShowNewImg(false); } // 初始化模板尺寸 / Cache template sizing info private void CacheTemplateInfo() { if (m_pSubRank != null) { m_rankHeight = m_pSubRank.GetSize().y; m_originBottom = m_pSubRank.GetPos().y; } if (m_contentRoot != null) { m_originWidth = m_contentRoot.rect.width; m_originHeight = m_contentRoot.rect.height; } } private void HideTemplates() { if (m_pSubRank != null) { m_pSubRank.Show(false); } if (m_pSubSkill != null) { m_pSubSkill.Show(false); } } // 初始化所有阶位子对话框 / Initialize all rank sub dialogs/// private void InitRankDlgs() { if (m_bAllocRankDlgs || m_pSubRank == null || m_contentRoot == null) { // #region agent log BMLogger.LogError($"[SkillSubList][H-E] InitRankDlgs skipped reason={(m_bAllocRankDlgs ? "already_alloc" : (m_pSubRank == null ? "no_sub_rank" : "no_content_root"))} allocRank={m_bAllocRankDlgs} subSkill={m_pSubSkill != null} contentRoot={m_contentRoot != null}"); // #endregion return; } m_bAllocRankDlgs = true; for (CECTaoistRank taoistRank = CECTaoistRank.GetBaseRankBegin(); taoistRank != CECTaoistRank.GetBaseRankEnd(); taoistRank = taoistRank.GetNext()) { CreateOneRankDlg(taoistRank); } for (CECTaoistRank taoistRank = CECTaoistRank.GetGodRankBegin(); taoistRank != CECTaoistRank.GetGodRankEnd(); taoistRank = taoistRank.GetNext()) { CreateOneRankDlg(taoistRank); } for (CECTaoistRank taoistRank = CECTaoistRank.GetEvilRankBegin(); taoistRank != CECTaoistRank.GetEvilRankEnd(); taoistRank = taoistRank.GetNext()) { CreateOneRankDlg(taoistRank); } } // ��ʼ�����������ڶԻ���һ���Է�����ڴ� / Initialize rank sub-dialogs once to avoid realloc private void CreateOneRankDlg(CECTaoistRank taoistRank) { AUISubDialog pSubRank = Instantiate(m_pSubRank, m_contentRoot, transform); pSubRank.SetName($"{m_pSubRank.GetName()}{taoistRank.GetID()}"); pSubRank.Show(false); m_rankSubDialogs[taoistRank.GetID()] = pSubRank; } // ���¶������Ի�����в��� / Reset dialog with all rank/skill sub dialogs public void ResetDialog() { m_skillSubDialogsMap.Clear(); m_skillSubCount = 0; m_curBottom = m_originBottom; foreach (var rank in m_rankSubDialogs.Values) { rank.Show(false); } foreach (var skill in m_skillSubDialogs) { skill.Show(false); } var skillModel = CECHostSkillModel.Instance; IReadOnlyDictionary> allRankProfSkills = skillModel?.GetAllRankProfSkills(); // #region agent log int totalCatalogSkills = allRankProfSkills != null ? allRankProfSkills.Values.Sum(l => l?.Count ?? 0) : -1; BMLogger.LogError($"[SkillSubList][H-A] ResetDialog start modelNull={skillModel == null} rankBuckets={allRankProfSkills?.Count ?? -1} catalogSkills={totalCatalogSkills} isEvil={IsEvil()} allocRank={m_bAllocRankDlgs} subSkillTpl={m_pSubSkill != null} contentRoot={m_contentRoot != null} hostNull={GetHostPlayer() == null}"); // #endregion for (CECTaoistRank taoistRank = CECTaoistRank.GetBaseRankBegin(); taoistRank != CECTaoistRank.GetBaseRankEnd(); taoistRank = taoistRank.GetNext()) { //BMLogger.LogError ("ResetDialog base rank " + taoistRank.GetName()); AddDlgsOfOneRank(taoistRank); } for (CECTaoistRank taoistRank = CECTaoistRank.GetGodRankBegin(); taoistRank != CECTaoistRank.GetGodRankEnd(); taoistRank = taoistRank.GetNext()) { //BMLogger.LogError("ResetDialog base rank " + taoistRank.GetName()); AddDlgsOfOneRank(taoistRank); } for (CECTaoistRank taoistRank = CECTaoistRank.GetEvilRankBegin(); taoistRank != CECTaoistRank.GetEvilRankEnd(); taoistRank = taoistRank.GetNext()) { //BMLogger.LogError("ResetDialog Evil rank " + taoistRank.GetName()); AddDlgsOfOneRank(taoistRank); } if (m_contentRoot != null) { FitSize(); ShowLastSelectedSkill(); } UpdateTotalSPText(); // #region agent log BMLogger.LogError($"[SkillSubList][H-E] ResetDialog end shownSkills={m_skillSubCount} rankBuckets={allRankProfSkills?.Count ?? -1} isEvil={IsEvil()} allocRank={m_bAllocRankDlgs}"); // #endregion } public void UpdateTotalSPText() { if (totalSPText != null && GetHostPlayer() != null) { totalSPText.text = " Nguyên Thần: " + GetHostPlayer().GetBasicProps().iSP.ToString() + ""; } } // ��鵯��ħ״̬ / Reset when switching between god/evil public void ResetGodEvil() { if (isActiveAndEnabled) { ResetDialog(); } } // �޸�ijһ����������״̬ / Refresh a single skill sub dialog private void UpdateOneSubDlg(int skillID) { //BMLogger.LogError("UpdateOneSubDlg"); if (!m_skillSubDialogsMap.TryGetValue(skillID, out var pSub)) { return; } CDlgSkillSubListItem subListItem = pSub; if(subListItem == null ) { return; } subListItem.UpdateSkill(skillID); subListItem.Show(true); if (GetSelectedSkillID() == skillID) { //GetGameUIMan()->m_pDlgSkillAction->ShowSkillTree(skillID); } } // ����һ�����漶��Ի��� / Show a rank sub dialog private void AddRankSubDig(int rankID) { if (!m_rankSubDialogs.TryGetValue(rankID, out var pSub)) { return; } pSub.Show(true); pSub.SetLabel(CECTaoistRank.GetTaoistRank(rankID).GetName()); //pSub.SetPos(0f, m_curBottom); //m_curBottom += m_rankHeight * m_windowScale; pSub.SetLabel(CECTaoistRank.GetTaoistRank(rankID).GetName()); } // ����һ�����ܶԻ��򣬵��øú����������UpdateOneSubDlg / Add a skill sub dialog then update it private void AddSkillSubDlg(int skillID, int rankID) { if (m_pSubSkill == null || m_contentRoot == null) { return; } if (m_skillSubCount >= m_skillSubDialogs.Count) { CDlgSkillSubListItem pSubSkill = Instantiate(m_pSubSkill, m_rankSubDialogs[rankID].transform); m_skillSubDialogs.Add(pSubSkill); } CDlgSkillSubListItem curSubSkill = m_skillSubDialogs[m_skillSubCount]; curSubSkill?.SetHighlight(false); m_skillSubDialogsMap[skillID] = curSubSkill; m_skillSubCount++; UpdateOneSubDlg(skillID); } // ��ijһ�����漶���Ӧ�����м���������Ի��� / Add dialogs for one rank private void AddDlgsOfOneRank(CECTaoistRank taoistRank) { CECHostSkillModel model = CECHostSkillModel.Instance; IReadOnlyDictionary> allRankProfSkills = model.GetAllRankProfSkills(); int rankID = taoistRank.GetID(); if (allRankProfSkills == null) { // #region agent log BMLogger.LogError($"[SkillSubList][H-A] AddDlgsOfOneRank skip reason=allRankProfSkills_null rankId={rankID}"); // #endregion return; } if (IsEvil() && taoistRank.IsGodRank()) { // #region agent log BMLogger.LogError($"[SkillSubList][H-C] AddDlgsOfOneRank skip reason=evil_hides_god rankId={rankID}"); // #endregion return; } else if (!IsEvil() && taoistRank.IsEvilRank()) { // #region agent log BMLogger.LogError($"[SkillSubList][H-C] AddDlgsOfOneRank skip reason=non_evil_hides_evil rankId={rankID}"); // #endregion return; } if (!allRankProfSkills.TryGetValue(rankID, out var rankItr) || rankItr == null || rankItr.Count == 0) { // #region agent log BMLogger.LogError($"[SkillSubList][H-A] AddDlgsOfOneRank skip reason=rank_empty rankId={rankID}"); // #endregion return; } List rankSkills = new List(); int overriddenSkipped = 0; foreach (var skillID in rankItr) { if (ElementSkill.IsOverridden((uint)skillID)) { overriddenSkipped++; BMLogger.LogError($"[SkillSubList][H-D] skill overridden skillId={skillID} rankId={rankID}"); continue; } /* bool bOnlyShowSkillCanLearn = GetGameUIMan()->m_pDlgSkillAction->IsOnlyShowSkillCanLearn(); if (bOnlyShowSkillCanLearn) { if (model.GetSkillFitLevel(skillID) == CECHostSkillModel::SKILL_NOT_FIT_LEVEL) { continue; } int curLevel = model.GetSkillCurrentLevel(skillID); int requiredItem = model.GetRequiredBook(skillID, curLevel + 1); if (requiredItem && !model.CheckPreItem(requiredItem)) { continue; } }*/ rankSkills.Add(skillID); } if (rankSkills.Count == 0) { // #region agent log BMLogger.LogError($"[SkillSubList][H-D] AddDlgsOfOneRank skip reason=all_overridden rankId={rankID} raw={rankItr.Count} overriddenSkipped={overriddenSkipped}"); // #endregion return; } // #region agent log BMLogger.LogError($"[SkillSubList][H-E] AddDlgsOfOneRank adding rankId={rankID} raw={rankItr.Count} shown={rankSkills.Count} overriddenSkipped={overriddenSkipped} isEvil={IsEvil()}"); // #endregion AddRankSubDig(rankID); rankSkills.Sort(); foreach (int skillID in rankSkills) { AddSkillSubDlg(skillID , rankID); } } private string GetRankName(int rankID) { // 尝试使用阶位名字,否则使用 ID / Use rank name if available, otherwise ID // TODO: wire into localization table once available return $"Rank {rankID}"; } // ����������洢��λ�õ���ȡֵ / Scroll helpers use the stored positions public void ScrollToShowSelectedSkill() { if (m_scrollRect == null || GetSelectedSkillID() == 0) { return; } if (!m_skillSubDialogsMap.TryGetValue(GetSelectedSkillID(), out var sub)) { return; } } // ׼�����Ľ��� / Prepare for layout change public bool OnChangeLayoutBegin() { foreach (var kv in m_rankSubDialogs) { Destroy(kv.Value.gameObject); } m_rankSubDialogs.Clear(); foreach (var dlg in m_skillSubDialogs) { Destroy(dlg.gameObject); } m_skillSubDialogs.Clear(); m_skillSubDialogsMap.Clear(); m_skillSubCount = 0; m_curBottom = 0f; return true; } // 布局变更结束时 / After layout change public void OnChangeLayoutEnd(bool bAllDone) { if (isActiveAndEnabled) { InitRankDlgs(); FitSize(); ShowLastSelectedSkill(); } } private void FitSize() { if (m_contentRoot == null) { return; } float height = Mathf.Max(m_curBottom, m_originHeight); m_contentRoot.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height); } private void ShowLastSelectedSkill() { int originSelected = GetSelectedSkillID(); SetSelectedSkillID(0); SelectSkill(originSelected); ScrollToShowSelectedSkill(); } public void SelectSkill(int skillID) { if (skillID != 0 && !m_skillSubDialogsMap.ContainsKey(skillID)) { skillID = ConvertSkillID(skillID); } if (skillID != 0 && !m_skillSubDialogsMap.ContainsKey(skillID)) { SetSelectedSkillID(0); return; } int originSelectedSkillID = GetSelectedSkillID(); if (originSelectedSkillID != 0 && m_skillSubDialogsMap.TryGetValue(originSelectedSkillID, out var originSub)) { originSub.GetComponent()?.SetHighlight(false); } if (skillID != 0 && m_skillSubDialogsMap.TryGetValue(skillID, out var newSub)) { newSub.GetComponent()?.SetHighlight(true); } SetSelectedSkillID(skillID); } public void EnableUpgrade(bool bEnable) { foreach (var kv in m_skillSubDialogsMap) { kv.Value.GetComponent()?.EnableUpgrade(bEnable); } } public int GetSelectedSkillID() { return m_selectedSkillId; } public void SetSelectedSkillID(int skillID) { m_selectedSkillId = skillID; } public bool IsEvil() { return m_isEvil; } public void SetEvil(bool value) { if (m_isEvil != value) { m_isEvil = value; ResetGodEvil(); } } // ���ܱ������Ӧ�����Ƿ�����б��� / Check whether skill or its converted counterpart exists public bool IsSkillOrConvertSkillExist(int skillID) { if (m_skillSubDialogsMap.ContainsKey(skillID)) { return true; } int convertSkillID = ConvertSkillID(skillID); return convertSkillID != 0 && m_skillSubDialogsMap.ContainsKey(convertSkillID); } private int ConvertSkillID(int skillID) { // 预留转换逻辑 / Placeholder for conversion logic return skillID; } // �м��ܱ������ˣ���Ҫ������������ / Handle model change notifications public void OnModelChange(CECSkillPanelChange q) { /* if (!GetGameUIMan().m_pDlgSkillAction.IsShow()) { return; }*/ if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_OVERRIDDEN) { ResetDialog(); } else if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_LEVEL_UP) { UpdateTotalSPText(); if (q.m_skillLevel == 1) { foreach (var kv in m_skillSubDialogsMap) { UpdateOneSubDlg(kv.Key); } } else { UpdateOneSubDlg(q.m_skillID); } } else if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_NPC) { //GetGameUIMan()->m_pDlgSkillAction->Show(false); } } } }