From 972104970da21f883312be7659b7232b0e6e5d89 Mon Sep 17 00:00:00 2001 From: VDH Date: Tue, 9 Dec 2025 19:53:32 +0700 Subject: [PATCH] copnvert --- .../Scripts/Managers/CECManager.cs | 2 + .../CSNetwork/C2SCommand/C2SCommand.cs | 1 + .../Scripts/Skills/EC_HostSkillModel.cs | 8 + .../PerfectWorld/Scripts/Skills/skill177.cs | 2 + .../PerfectWorld/Scripts/Skills/skill178.cs | 2 + Assets/PerfectWorld/Scripts/Skills/skill54.cs | 2 + Assets/PerfectWorld/Scripts/Skills/skill56.cs | 2 + Assets/PerfectWorld/Scripts/Skills/skill57.cs | 2 + Assets/PerfectWorld/Scripts/Skills/skill58.cs | 2 + Assets/PerfectWorld/Scripts/Skills/skill76.cs | 2 + .../Scripts/UI/Dialogs/CDlgSkillSubList.cs | 621 ++++++++++++++++++ .../UI/Dialogs/CDlgSkillSubList.cs.meta | 2 + Assets/Prefabs/UI/SkillUI.prefab | 18 +- Assets/Scripts/CECUIManager.cs | 7 +- .../LiberationSans SDF - Fallback.asset | 122 +--- ProjectSettings/QualitySettings.asset | 77 +-- 16 files changed, 673 insertions(+), 199 deletions(-) create mode 100644 Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs create mode 100644 Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs.meta diff --git a/Assets/PerfectWorld/Scripts/Managers/CECManager.cs b/Assets/PerfectWorld/Scripts/Managers/CECManager.cs index d2c0fa11b0..bd10413956 100644 --- a/Assets/PerfectWorld/Scripts/Managers/CECManager.cs +++ b/Assets/PerfectWorld/Scripts/Managers/CECManager.cs @@ -123,6 +123,8 @@ namespace BrewMonster.Managers + + diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs index 8137d2935b..8d862ae804 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs @@ -1,4 +1,5 @@ +using System.Runtime.InteropServices; using UnityEngine; namespace CSNetwork.C2SCommand diff --git a/Assets/PerfectWorld/Scripts/Skills/EC_HostSkillModel.cs b/Assets/PerfectWorld/Scripts/Skills/EC_HostSkillModel.cs index 4a3fd88d91..233dd99e62 100644 --- a/Assets/PerfectWorld/Scripts/Skills/EC_HostSkillModel.cs +++ b/Assets/PerfectWorld/Scripts/Skills/EC_HostSkillModel.cs @@ -34,6 +34,14 @@ namespace BrewMonster.Scripts.Skills private bool m_bInitialized; private Octets m_npcListData; + /// + /// 获取当前职业的全部技能映射(阶位 -> 技能列表) / Get rank-to-skills map for current profession. + /// + public IReadOnlyDictionary> GetAllRankProfSkills() + { + return m_allRankProfSkills; + } + public void Initialize() { // Çå¿ÕËùÓм¼ÄÜ£¬·ÀÖ¹ÒòΪ¶à¸ö½ÇÉ«µÇ¼µ¼ÖÂÖØ¸´¼ÓÔØ¼¼ÄÜ diff --git a/Assets/PerfectWorld/Scripts/Skills/skill177.cs b/Assets/PerfectWorld/Scripts/Skills/skill177.cs index 93bab0e02e..bfa2b8ec42 100644 --- a/Assets/PerfectWorld/Scripts/Skills/skill177.cs +++ b/Assets/PerfectWorld/Scripts/Skills/skill177.cs @@ -233,3 +233,5 @@ namespace BrewMonster + + diff --git a/Assets/PerfectWorld/Scripts/Skills/skill178.cs b/Assets/PerfectWorld/Scripts/Skills/skill178.cs index b4e747f6f9..190223f253 100644 --- a/Assets/PerfectWorld/Scripts/Skills/skill178.cs +++ b/Assets/PerfectWorld/Scripts/Skills/skill178.cs @@ -233,3 +233,5 @@ namespace BrewMonster + + diff --git a/Assets/PerfectWorld/Scripts/Skills/skill54.cs b/Assets/PerfectWorld/Scripts/Skills/skill54.cs index 1cd866e88a..195c7cab7a 100644 --- a/Assets/PerfectWorld/Scripts/Skills/skill54.cs +++ b/Assets/PerfectWorld/Scripts/Skills/skill54.cs @@ -330,3 +330,5 @@ namespace BrewMonster + + diff --git a/Assets/PerfectWorld/Scripts/Skills/skill56.cs b/Assets/PerfectWorld/Scripts/Skills/skill56.cs index 9a1f4ca568..b2c127e24a 100644 --- a/Assets/PerfectWorld/Scripts/Skills/skill56.cs +++ b/Assets/PerfectWorld/Scripts/Skills/skill56.cs @@ -324,3 +324,5 @@ namespace BrewMonster + + diff --git a/Assets/PerfectWorld/Scripts/Skills/skill57.cs b/Assets/PerfectWorld/Scripts/Skills/skill57.cs index da9ca49426..7e30059c6c 100644 --- a/Assets/PerfectWorld/Scripts/Skills/skill57.cs +++ b/Assets/PerfectWorld/Scripts/Skills/skill57.cs @@ -335,3 +335,5 @@ namespace BrewMonster + + diff --git a/Assets/PerfectWorld/Scripts/Skills/skill58.cs b/Assets/PerfectWorld/Scripts/Skills/skill58.cs index 5009a7cc28..a4c776189e 100644 --- a/Assets/PerfectWorld/Scripts/Skills/skill58.cs +++ b/Assets/PerfectWorld/Scripts/Skills/skill58.cs @@ -328,3 +328,5 @@ namespace BrewMonster + + diff --git a/Assets/PerfectWorld/Scripts/Skills/skill76.cs b/Assets/PerfectWorld/Scripts/Skills/skill76.cs index be2d1cd204..6351f404d4 100644 --- a/Assets/PerfectWorld/Scripts/Skills/skill76.cs +++ b/Assets/PerfectWorld/Scripts/Skills/skill76.cs @@ -238,3 +238,5 @@ namespace BrewMonster + + diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs new file mode 100644 index 0000000000..a099392dd4 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs @@ -0,0 +1,621 @@ +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 AUISubDialog m_pSubSkill; + + [Header("Layout")] + [SerializeField] private RectTransform m_contentRoot; + [SerializeField] private ScrollRect m_scrollRect; + [SerializeField] private float m_windowScale = 1f; + + [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; + } + + 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_pSubSkill != null) + { + m_skillHeight = m_pSubSkill.GetSize().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) + { + return; + } + m_bAllocRankDlgs = true; + + foreach (int rankId in EnumerateAllRankIds()) + { + CreateOneRankDlg(rankId); + } + } + + // ��ʼ�����������ڶԻ���һ���Է�����ڴ� / Initialize rank sub-dialogs once to avoid realloc + private void CreateOneRankDlg(int rankID) + { + AUISubDialog pSubRank = Instantiate(m_pSubRank, m_contentRoot); + pSubRank.SetName($"{m_pSubRank.GetName()}{rankID}"); + pSubRank.Show(false); + + m_rankSubDialogs[rankID] = 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); + } + + IReadOnlyDictionary> allRankProfSkills = CECHostSkillModel.Instance?.GetAllRankProfSkills(); + + foreach (int rankId in EnumerateBaseRankIds()) + { + AddDlgsOfOneRank(rankId, allRankProfSkills); + } + + foreach (int rankId in EnumerateGodRankIds()) + { + AddDlgsOfOneRank(rankId, allRankProfSkills); + } + + foreach (int rankId in EnumerateEvilRankIds()) + { + AddDlgsOfOneRank(rankId, allRankProfSkills); + } + + if (m_contentRoot != null) + { + FitSize(); + ShowLastSelectedSkill(); + } + } + + // ��鵯��ħ״̬ / Reset when switching between god/evil + public void ResetGodEvil() + { + if (isActiveAndEnabled) + { + ResetDialog(); + } + } + + // �޸�ijһ����������״̬ / Refresh a single skill sub dialog + private void UpdateOneSubDlg(int skillID) + { + if (!m_skillSubDialogsMap.TryGetValue(skillID, out var pSub)) + { + return; + } + + CDlgSkillSubListItem subListItem = pSub.GetComponent(); + subListItem?.UpdateSkill(skillID); + + if (GetSelectedSkillID() == skillID) + { + // 选中时可在此扩展树状展示 / Hook skill tree here if needed + } + } + + // ����һ�����漶��Ի��� / Show a rank sub dialog + private void AddRankSubDig(int rankID) + { + if (!m_rankSubDialogs.TryGetValue(rankID, out var pSub)) + { + return; + } + + pSub.Show(true); + pSub.SetPos(0f, m_curBottom); + m_curBottom += m_rankHeight * m_windowScale; + + TextMeshProUGUI label = pSub.GetComponentInChildren(true); + if (label != null) + { + label.text = GetRankName(rankID); + } + } + + // ����һ�����ܶԻ��򣬵��øú����������UpdateOneSubDlg / Add a skill sub dialog then update it + private void AddSkillSubDlg(int skillID) + { + if (m_pSubSkill == null || m_contentRoot == null) + { + return; + } + + if (m_skillSubCount >= m_skillSubDialogs.Count) + { + AUISubDialog pSubSkill = Instantiate(m_pSubSkill, m_contentRoot); + pSubSkill.SetName($"{m_pSubSkill.GetName()}{m_skillSubDialogs.Count}"); + m_skillSubDialogs.Add(pSubSkill); + } + + AUISubDialog curSubSkill = m_skillSubDialogs[m_skillSubCount]; + CDlgSkillSubListItem item = curSubSkill.GetComponent(); + item?.SetHighlight(false); + + curSubSkill.SetPos(0f, m_curBottom); + curSubSkill.Show(true); + curSubSkill.SetData(Mathf.RoundToInt(m_curBottom)); + m_curBottom += m_skillHeight * m_windowScale; + + m_skillSubDialogsMap[skillID] = curSubSkill; + m_skillSubCount++; + UpdateOneSubDlg(skillID); + } + + // ��ijһ�����漶���Ӧ�����м���������Ի��� / Add dialogs for one rank + private void AddDlgsOfOneRank(int rankID, IReadOnlyDictionary> allRankProfSkills) + { + if (allRankProfSkills == null) + { + return; + } + + if (IsEvil() && IsGodRank(rankID)) + { + return; + } + else if (!IsEvil() && IsEvilRank(rankID)) + { + return; + } + + if (!allRankProfSkills.TryGetValue(rankID, out var rankSkills) || rankSkills == null || rankSkills.Count == 0) + { + return; + } + + AddRankSubDig(rankID); + foreach (int skillID in rankSkills) + { + AddSkillSubDlg(skillID); + } + } + + private string GetRankName(int rankID) + { + // 尝试使用阶位名字,否则使用 ID / Use rank name if available, otherwise ID + // TODO: wire into localization table once available + return $"Rank {rankID}"; + } + + private static IEnumerable EnumerateAllRankIds() + { + return CECTaoistRank.TaoistRankIDs; + } + + private static IEnumerable EnumerateBaseRankIds() + { + return CECTaoistRank.TaoistRankIDs.Take((int)ToaistRank.BaseRankCount); + } + + private static IEnumerable EnumerateGodRankIds() + { + return CECTaoistRank.TaoistRankIDs.Skip((int)ToaistRank.BaseRankCount) + .Take((int)ToaistRank.GodRankCount); + } + + private static IEnumerable EnumerateEvilRankIds() + { + return CECTaoistRank.TaoistRankIDs.Skip((int)ToaistRank.BaseRankCount + (int)ToaistRank.GodRankCount); + } + + // ����������洢��λ�õ���ȡֵ / 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; + } + + float subTop = sub.GetPos().y; + float subBottom = subTop + sub.GetSize().y; + float expandedHeight = m_curBottom; + float viewportHeight = m_scrollRect.viewport != null ? m_scrollRect.viewport.rect.height : expandedHeight; + + if (viewportHeight >= expandedHeight || expandedHeight <= 0f) + { + return; + } + + float mid = (subTop + subBottom) * 0.5f; + float target = Mathf.Clamp01(mid / expandedHeight); + m_scrollRect.verticalNormalizedPosition = 1f - target; + } + + // ׼�����Ľ��� / 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(CECHostSkillModel p, CECSkillPanelChange q) + { + if (q == null) + { + return; + } + + if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_OVERRIDDEN) + { + ResetDialog(); + } + else if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_LEVEL_UP) + { + 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) + { + // NPC变化时原逻辑隐藏技能树 / Original logic hides skill tree when NPC changes + } + } + } + + [DisallowMultipleComponent] + public class AUISubDialog : MonoBehaviour + { + [SerializeField] private AUIDialog m_subDialog; + [SerializeField] private RectTransform m_rectTransform; + private int m_data; + + private void Reset() + { + if (m_rectTransform == null) + { + m_rectTransform = transform as RectTransform; + } + if (m_subDialog == null) + { + m_subDialog = GetComponent(); + } + } + + public void SetDialog(AUIDialog dialog) + { + m_subDialog = dialog; + } + + public AUIDialog GetSubDialog() + { + return m_subDialog; + } + + public string GetName() + { + return name; + } + + public void SetName(string newName) + { + name = newName; + } + + public Vector2Int GetSize() + { + if (m_rectTransform == null) + { + m_rectTransform = transform as RectTransform; + } + + return m_rectTransform != null + ? Vector2Int.RoundToInt(m_rectTransform.rect.size) + : Vector2Int.zero; + } + + public Vector2 GetPos() + { + if (m_rectTransform == null) + { + m_rectTransform = transform as RectTransform; + } + + return m_rectTransform != null ? m_rectTransform.anchoredPosition : Vector2.zero; + } + + public void SetPos(float x, float y) + { + if (m_rectTransform == null) + { + m_rectTransform = transform as RectTransform; + } + + if (m_rectTransform != null) + { + m_rectTransform.anchoredPosition = new Vector2(x, y); + } + } + + public void Show(bool value) + { + gameObject.SetActive(value); + } + + public void SetData(int data) + { + m_data = data; + } + + public int GetData() + { + return m_data; + } + } + + [DisallowMultipleComponent] + public class CDlgSkillSubListItem : MonoBehaviour + { + [SerializeField] private TextMeshProUGUI m_nameText; + [SerializeField] private GameObject m_highlight; + + private int m_skillID; + + public void UpdateSkill(int skillID) + { + m_skillID = skillID; + if (m_nameText != null) + { + m_nameText.text = CECHostSkillModel.Instance?.GetSkillName(skillID) ?? $"Skill {skillID}"; + } + } + + public void SetHighlight(bool bHighlight) + { + if (m_highlight != null) + { + m_highlight.SetActive(bHighlight); + } + } + + public void EnableUpgrade(bool bEnable) + { + Button btn = GetComponentInChildren