From 6fb8e223555e434fe3cd10cb8de8aa7dc253e7a4 Mon Sep 17 00:00:00 2001 From: Tran Hai Nam Date: Tue, 19 May 2026 15:25:59 +0700 Subject: [PATCH] Fix some bug --- .../AddressableAssetSettings.asset | 2 +- .../gfx/人物/技能/武侠/霸王断岳施放.prefab | 8 +- .../人物/唐刀/细刀16品/细刀16品.prefab | 4 +- .../weapons/人物/弓弩/弓/18品弓/18品弓.prefab | 6 +- .../weapons/人物/弓弩/弩/18品弩/18品弩.prefab | 4 +- .../人物/弓弩/弹弓/19品弹弓/19品弹弓.prefab | 4 +- .../拳套/短刃/19品短刃/19品短刃_右.prefab | 4 +- .../斧锤/双手双斧/18品双斧/18品双斧.prefab | 4 +- .../人物/法器/15品法器/15品法器橙.prefab | 6 +- .../人物/长兵/重头/19品镗/19品镗.prefab | 4 +- .../人物/长兵/重头/紫阳槊/紫阳槊极品.prefab | 6 +- .../Scripts/AnimScenePlayerBootstrap.cs | 118 ++++++++-- .../Scripts/Debug/SkillTriggerPanel.cs | 214 +++++++++++++----- .../Editor/AnimScenePlayerBootstrapEditor.cs | 21 ++ .../Scripts/Skills/EC_HostSkillModel.cs | 62 ++++- Assets/Scripts/CECHostPlayer.Skill.cs | 62 +++++ 16 files changed, 434 insertions(+), 95 deletions(-) diff --git a/Assets/AddressableAssetsData/AddressableAssetSettings.asset b/Assets/AddressableAssetsData/AddressableAssetSettings.asset index ef5075b42c..c6e153cd9a 100644 --- a/Assets/AddressableAssetsData/AddressableAssetSettings.asset +++ b/Assets/AddressableAssetsData/AddressableAssetSettings.asset @@ -15,7 +15,7 @@ MonoBehaviour: m_DefaultGroup: 712e3991f28e549e7a56ee582a977810 m_currentHash: serializedVersion: 2 - Hash: 584471775533227dbfd66c0814b46e32 + Hash: 00000000000000000000000000000000 m_OptimizeCatalogSize: 0 m_BuildRemoteCatalog: 0 m_CatalogRequestsTimeout: 0 diff --git a/Assets/ModelRenderer/Art/Gfx/gfx/人物/技能/武侠/霸王断岳施放.prefab b/Assets/ModelRenderer/Art/Gfx/gfx/人物/技能/武侠/霸王断岳施放.prefab index ae8b1f99fb..9451c24919 100644 --- a/Assets/ModelRenderer/Art/Gfx/gfx/人物/技能/武侠/霸王断岳施放.prefab +++ b/Assets/ModelRenderer/Art/Gfx/gfx/人物/技能/武侠/霸王断岳施放.prefab @@ -4869,7 +4869,7 @@ Transform: m_GameObject: {fileID: 4197944621747409826} serializedVersion: 2 m_LocalRotation: {x: -0.6878776, y: -0.16378161, z: 0.16378164, w: 0.6878776} - m_LocalPosition: {x: 0.024, y: 0.554, z: -0.33} + m_LocalPosition: {x: 0.26, y: 1.51, z: -0.52} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: @@ -5595,7 +5595,7 @@ ParticleSystem: sphericalDirectionAmount: 0 randomPositionAmount: 0 radius: - value: 0.71 + value: 2.13 mode: 0 spread: 0 speed: @@ -19445,8 +19445,8 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 + m_LocalScale: {x: 3, y: 3, z: 3} + m_ConstrainProportionsScale: 1 m_Children: [] m_Father: {fileID: 1604809390761698253} m_LocalEulerAnglesHint: {x: -90, y: 0, z: 0} diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/唐刀/细刀16品/细刀16品.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/唐刀/细刀16品/细刀16品.prefab index c67796562d..0f324b9fff 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/唐刀/细刀16品/细刀16品.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/唐刀/细刀16品/细刀16品.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 4274349585449340130} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} --- !u!33 &7795735887883509743 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弓/18品弓/18品弓.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弓/18品弓/18品弓.prefab index 4c52cbfd74..d24f975593 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弓/18品弓/18品弓.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弓/18品弓/18品弓.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 4135001540345507112} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: -0.1, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} --- !u!33 &5782369747155273987 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弩/18品弩/18品弩.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弩/18品弩/18品弩.prefab index 0cdcd056f2..241a14a756 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弩/18品弩/18品弩.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弩/18品弩/18品弩.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2368932797394218666} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: 0.35355344, y: 0.6123724, z: 0.6123724, w: 0.35355344} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: -30, y: 90, z: 90} --- !u!33 &6354786712980373978 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弹弓/19品弹弓/19品弹弓.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弹弓/19品弹弓/19品弹弓.prefab index b2a2315223..13960c7c33 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弹弓/19品弹弓/19品弹弓.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/弓弩/弹弓/19品弹弓/19品弹弓.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 486393464438265562} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} --- !u!33 &2795371212256588815 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/拳套/短刃/19品短刃/19品短刃_右.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/拳套/短刃/19品短刃/19品短刃_右.prefab index 648af18f1b..defbe42bff 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/拳套/短刃/19品短刃/19品短刃_右.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/拳套/短刃/19品短刃/19品短刃_右.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5042710232424246754} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} --- !u!33 &7463675474240568897 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/斧锤/双手双斧/18品双斧/18品双斧.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/斧锤/双手双斧/18品双斧/18品双斧.prefab index 7bf217925e..c8210da2ad 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/斧锤/双手双斧/18品双斧/18品双斧.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/斧锤/双手双斧/18品双斧/18品双斧.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 192856137541653222} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: -90, y: 180, z: 0} --- !u!33 &7385562017347778284 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/法器/15品法器/15品法器橙.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/法器/15品法器/15品法器橙.prefab index 1cea901def..078be3d006 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/法器/15品法器/15品法器橙.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/法器/15品法器/15品法器橙.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5834653072341985716} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalRotation: {x: 0.3535534, y: 0.61237246, z: -0.3535534, w: 0.61237246} + m_LocalPosition: {x: 0, y: -0.2, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 60, y: 90, z: 0} --- !u!33 &5428329696048806453 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/长兵/重头/19品镗/19品镗.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/长兵/重头/19品镗/19品镗.prefab index 8677254638..f898b8b38d 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/长兵/重头/19品镗/19品镗.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/长兵/重头/19品镗/19品镗.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6619641526290080649} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: 0, y: 0.7071068, z: -0.7071068, w: 0} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 90, y: 180, z: 0} --- !u!33 &7228491550620403586 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/长兵/重头/紫阳槊/紫阳槊极品.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/长兵/重头/紫阳槊/紫阳槊极品.prefab index 36dcf60966..9d0b8f7bc5 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/长兵/重头/紫阳槊/紫阳槊极品.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/长兵/重头/紫阳槊/紫阳槊极品.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1020594218048739884} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0.73, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} --- !u!33 &3048989088492932353 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/PerfectWorld/Scripts/AnimScenePlayerBootstrap.cs b/Assets/PerfectWorld/Scripts/AnimScenePlayerBootstrap.cs index 9e71c4732b..2c5107a173 100644 --- a/Assets/PerfectWorld/Scripts/AnimScenePlayerBootstrap.cs +++ b/Assets/PerfectWorld/Scripts/AnimScenePlayerBootstrap.cs @@ -1,6 +1,8 @@ +using System.Collections.Generic; using BrewMonster; using BrewMonster.Network; using BrewMonster.Scripts; +using BrewMonster.Scripts.Skills; using UnityEngine; namespace PerfectWorld.Scripts @@ -18,7 +20,7 @@ namespace PerfectWorld.Scripts /// /// Test scene only: bootstraps model load. After each successful , - /// optionally applies serialized weapon prefabs via (sets m_uAttackType like equip data). + /// applies serialized weapon prefabs via (sets m_uAttackType like equip data). /// After each load, destroys the previous major model instance so it does not linger in the hierarchy. /// Optional: discard the whole host instance and instantiate a fresh prefab when switching role (see ). /// @@ -28,6 +30,14 @@ namespace PerfectWorld.Scripts [Tooltip("Scene host player. Do not put this bootstrap component on the same GameObject as the host if you enable Replace host on role switch.")] [SerializeField] private CECHostPlayer player; + [SerializeField] + private Camera cameraObject; + [SerializeField] + private List cameraPoses; + [SerializeField] + [Range(0, 10)] + private int activeCameraPos; + [Header("Initial Role")] [SerializeField] @@ -43,12 +53,9 @@ namespace PerfectWorld.Scripts [Tooltip("Which weaponByActionType row to apply after load / when using Re-apply in the custom inspector.")] [SerializeField] - [Range(0, 14)] + [Range(0, 10)] private int activeWeaponActionTypeIndex; - [SerializeField] - private bool applyWeaponAfterModelLoad = true; - [Header("Animation scene — element data compat")] [Tooltip( "If true, sets m_iFashionWeaponType = -1 on the host so PlayAction / GetShowingWeaponType do not call IsFashionWeaponTypeFit with missing DT_FASHION_WEAPON_CONFIG (avoids null action_mask NRE). Disable only if you load that config row.")] @@ -62,6 +69,15 @@ namespace PerfectWorld.Scripts [SerializeField] private bool bindPlayerVisualAfterModelLoad = true; + [Header("Animation scene — skill catalog")] + [Tooltip("Match CDlgSkillSubList god/evil path when building the debug skill grid.")] + [SerializeField] + private bool isEvilSkillPath; + + [Tooltip("Default level for skills injected from CECHostSkillModel in anim scenes.")] + [SerializeField] + private int skillCatalogLevel = 1; + [Header("Test-only — cleanup & host swap")] [Tooltip("After SetPlayerModel, Destroy the previous major .ecm instance (frees scene objects left by re-load).")] [SerializeField] @@ -88,6 +104,26 @@ namespace PerfectWorld.Scripts await BootstrapAsync((byte)profession, (byte)gender, fromInitialStart: true); } + public void ChangeCameraPos(int i) + { + if(i<0) + activeCameraPos = cameraPoses.Count-1; + if (i>= cameraPoses.Count ) + activeCameraPos = 0; + else + activeCameraPos = i; + cameraObject.transform.parent = cameraPoses[activeCameraPos]; + cameraObject.transform.localRotation = default; + cameraObject.transform.localPosition = default; + } + public void ChangeNextCamera() + { + ChangeCameraPos (++activeCameraPos ); + } + public void ChangePreviosCamera() + { + ChangeCameraPos (--activeCameraPos ); + } /// Swap profession/gender at runtime (async load inside). public void SwitchRole(Profession newProfession, Gender newGender) @@ -190,6 +226,28 @@ namespace PerfectWorld.Scripts } } + /// + /// Re-apply weapon, rebuild skill catalog for current role, and refresh SkillTriggerPanel. + /// 重新应用武器、重建技能目录并刷新技能面板。 + /// + public void ResetSkillPanel(bool filterByRestrictions) + { + if (player == null) + { + Debug.LogWarning("[AnimSceneBootstrap] ResetSkillPanel: player is null."); + return; + } + + ApplyWeaponForActiveSlot(); + RefreshSkillTriggerPanel(filterByRestrictions); + } + + /// Reload skill grid showing only skills usable with current weapon/form/env. + public void ResetSkillsWithRestrictions() => ResetSkillPanel(filterByRestrictions: true); + + /// Reload skill grid with all catalog skills (no weapon/form/env filter). + public void ResetSkillsWithoutRestrictions() => ResetSkillPanel(filterByRestrictions: false); + private void ReplaceHostPlayerInstance() { if (hostPlayerPrefab == null) @@ -229,6 +287,7 @@ namespace PerfectWorld.Scripts _busy = true; try { + ChangeCameraPos(activeCameraPos); Debug.Log("[AnimSceneBootstrap] AnimScenePlayerBootstrap — waiting for ElementDataManProvider..."); int waitedFrames = 0; while (!ElementDataManProvider.IsDataLoaded) @@ -277,15 +336,9 @@ namespace PerfectWorld.Scripts await player.SetPlayerModel(prof, gen); Debug.Log("[AnimSceneBootstrap] SetPlayerModel pipeline finished."); - if (player != null) - { - EC_Game.GetGameRun()?.RegisterAnimSceneHostPlayer(player); - } + ApplyWeaponForActiveSlot(); - if (applyWeaponAfterModelLoad && player != null) - { - ApplyWeaponForActiveSlot(); - } + AnimSceneInitSkillModelAndRefreshPanel(prof, gen); AnimSceneBindPlayerVisualIfEnabled(); @@ -309,5 +362,44 @@ namespace PerfectWorld.Scripts _busy = false; } } + + /// + /// Sync profession/gender, rebuild CECHostSkillModel for the current role, and refresh SkillTriggerPanel. + /// SetPlayerModel loads visuals only — m_iProfession is not updated otherwise, and skill catalog init + /// is skipped in anim scenes (no LoadPlayerSkeleton → OnAllResourceReady). + /// + /// 同步职业/性别,重建 CECHostSkillModel,并刷新 SkillTriggerPanel。 + /// + private void AnimSceneInitSkillModelAndRefreshPanel(byte prof, byte gen) + { + if (player == null) + { + return; + } + + player.m_iProfession = prof; + player.m_iGender = gen; + + EC_Game.GetGameRun()?.RegisterAnimSceneHostPlayer(player); + + SkillStubs.Init(); + CECHostSkillModel.Instance.Initialize(prof); + Debug.Log($"[AnimSceneBootstrap] CECHostSkillModel initialized for profession={prof}, " + + $"catalogSkills={CECHostSkillModel.Instance.CollectSkillSubListSkillIds(isEvilSkillPath).Count}."); + + RefreshSkillTriggerPanel(filterByRestrictions: false); + } + + private void RefreshSkillTriggerPanel(bool filterByRestrictions) + { + if (SkillTriggerPanel.Instance == null) + { + return; + } + + SkillTriggerPanel.Instance.SetHostPlayer(player); + SkillTriggerPanel.Instance.SetEvilSkillPath(isEvilSkillPath); + SkillTriggerPanel.Instance.ResetSkillsFromSkillModel(filterByRestrictions, skillCatalogLevel); + } } } diff --git a/Assets/PerfectWorld/Scripts/Debug/SkillTriggerPanel.cs b/Assets/PerfectWorld/Scripts/Debug/SkillTriggerPanel.cs index ad24ef7b4b..097aab9c2c 100644 --- a/Assets/PerfectWorld/Scripts/Debug/SkillTriggerPanel.cs +++ b/Assets/PerfectWorld/Scripts/Debug/SkillTriggerPanel.cs @@ -59,6 +59,11 @@ namespace BrewMonster [Tooltip("When enabled, hides skills that fail weapon/form/move-env restrictions. Disable to show ALL positive skills regardless of restrictions.")] [SerializeField] private bool filterByRestrictions = false; + [Tooltip("Match CDlgSkillSubList god/evil path: false = base+god ranks, true = base+evil ranks.")] + [SerializeField] private bool isEvilSkillPath; + + [SerializeField] private int skillCatalogLevel = 1; + /// /// World position of the draggable target marker, read by CECSkillGfxMan.get_pos_by_id. /// 可拖动目标标记的世界坐标,由 CECSkillGfxMan.get_pos_by_id 读取。 @@ -101,6 +106,19 @@ namespace BrewMonster gameRun.RegisterAnimSceneHostPlayer(player); } + /// + /// Anim scene host swap: keep panel player reference in sync with bootstrap. + /// 动画场景切换角色时同步面板上的主角引用。 + /// + public void SetHostPlayer(CECHostPlayer host) + { + if (host == null) + return; + + player = host; + RegisterSceneHostWithGameRun(); + } + /// Target id for / GFX composer (self = host cid, else marker NPC id). private int ResolveLocalCastTargetId(CECSkill skill) { @@ -114,14 +132,11 @@ namespace BrewMonster } /// - /// Polls every 0.5 s until the host player has skills and CECGameUIMan is initialized, - /// then calls Refresh() once. If no server skill data arrives within - /// seconds, injects all config skills directly from SkillStub.map so the panel works offline. + /// Polls until CECGameUIMan is ready and the host has skills (server, skill model, or config fallback). /// - /// 每 0.5 秒轮询,直到主角已有技能且 CECGameUIMan 初始化完毕,再调用一次 Refresh()。 - /// 若 k_InjectFallbackSecs 秒内未收到服务端技能数据,则直接从 SkillStub.map 注入所有配置技能,以便离线使用。 + /// 轮询直到 UI 图集与技能数据就绪(服务端、CECHostSkillModel 或配置回退)。 /// - private const float k_InjectFallbackSecs = 2f; + private const float k_RefreshWaitTimeoutSecs = 30f; private IEnumerator RefreshWhenReady() { var wait = new WaitForSeconds(0.5f); @@ -135,17 +150,23 @@ namespace BrewMonster yield return wait; } - // Wait for skills, but fall back to config injection after timeout. - // 等待技能数据,超时后回退到配置注入。 - while (player != null && player.GetPositiveSkillNum() == 0) + ResolveHostPlayerReference(); + + // Wait for skills: server list, CECHostSkillModel catalog (anim scene), or config fallback. + // 等待技能:服务端列表、CECHostSkillModel 目录(动画场景)或配置回退。 + while (player != null && !HasSkillCatalogOrPositiveSkills()) { - if (elapsed >= k_InjectFallbackSecs) + if (TryInjectFromSkillModel()) + break; + + if (elapsed >= k_RefreshWaitTimeoutSecs) { - Debug.Log("[SkillTriggerPanel] No server skills after " + - $"{k_InjectFallbackSecs}s — injecting all config skills for offline debug."); + Debug.LogWarning("[SkillTriggerPanel] No skills after " + + $"{k_RefreshWaitTimeoutSecs}s — falling back to SkillStub.map injection."); player.InjectDebugSkillsFromConfig(); break; } + elapsed += 0.5f; yield return wait; } @@ -153,6 +174,36 @@ namespace BrewMonster Refresh(); } + private void ResolveHostPlayerReference() + { + if (player != null) + return; + + player = EC_Game.GetGameRun()?.GetHostPlayer(); + } + + private bool HasSkillCatalogOrPositiveSkills() + { + if (player != null && player.GetPositiveSkillNum() > 0) + return true; + + List catalog = CECHostSkillModel.Instance?.CollectSkillSubListSkillIds(isEvilSkillPath); + return catalog != null && catalog.Count > 0; + } + + private bool TryInjectFromSkillModel() + { + if (player == null) + return false; + + List catalog = CECHostSkillModel.Instance?.CollectSkillSubListSkillIds(isEvilSkillPath); + if (catalog == null || catalog.Count == 0) + return false; + + player.InjectSkillsFromSkillModel(skillCatalogLevel, isEvilSkillPath); + return true; + } + /// /// Loads every skill defined in SkillStub.map (config) directly into the player's skill list, /// bypassing the server skill message. Use this when testing locally without a server. @@ -171,6 +222,46 @@ namespace BrewMonster Refresh(); } + /// + /// Rebuild host positive skills from (same catalog as CDlgSkillSubList) and refresh the grid. + /// AnimScenePlayerBootstrap calls this after each model / role switch. + /// + /// 从 CECHostSkillModel 重建主角正向技能并刷新网格(与 CDlgSkillSubList 相同目录)。 + /// + [ContextMenu("Debug: Refresh From Skill Model")] + public void RefreshFromSkillModel(int level = -1) + { + ResolveHostPlayerReference(); + if (player == null) + { + Debug.LogWarning("[SkillTriggerPanel] RefreshFromSkillModel: no host player."); + return; + } + + if (level > 0) + skillCatalogLevel = level; + + player.InjectSkillsFromSkillModel(skillCatalogLevel, isEvilSkillPath); + + List catalogSkills = player.BuildSkillSubListSkills(skillCatalogLevel, isEvilSkillPath); + PopulateSkillGrid(catalogSkills, catalogSkills.Count); + } + + public void SetEvilSkillPath(bool isEvil) + { + isEvilSkillPath = isEvil; + } + + /// + /// Reload from CECHostSkillModel and optionally hide skills that fail weapon/form/env checks. + /// 从技能目录重新加载;applyRestrictions 为 true 时按武器/形态/环境过滤。 + /// + public void ResetSkillsFromSkillModel(bool applyRestrictions, int level = -1) + { + filterByRestrictions = applyRestrictions; + RefreshFromSkillModel(level); + } + /// /// Clears and repopulates the skill grid from the host player's current positive skill list. /// Call again after equipping a different weapon or changing shape/form. @@ -197,12 +288,14 @@ namespace BrewMonster return; } - // Clear existing buttons / 清空已有按钮 - foreach (Transform child in skillGridContainer) - Destroy(child.gameObject); + var catalogSkills = player.BuildSkillSubListSkills(skillCatalogLevel, isEvilSkillPath); + if (catalogSkills.Count > 0) + { + PopulateSkillGrid(catalogSkills, catalogSkills.Count); + return; + } int total = player.GetPositiveSkillNum(); - if (total == 0) { Debug.LogWarning("[SkillTriggerPanel] GetPositiveSkillNum() = 0. " + @@ -211,6 +304,22 @@ namespace BrewMonster return; } + var positiveSkills = new List(total); + for (int i = 0; i < total; i++) + { + CECSkill skill = player.GetPositiveSkillByIndex(i); + if (skill != null) + positiveSkills.Add(skill); + } + + PopulateSkillGrid(positiveSkills, total); + } + + private void PopulateSkillGrid(IReadOnlyList skills, int totalListed) + { + foreach (Transform child in skillGridContainer) + Destroy(child.gameObject); + CECGameUIMan uiMan = CECUIManager.Instance?.GetInGameUIMan(); if (uiMan == null) { @@ -221,9 +330,9 @@ namespace BrewMonster int added = 0; int filtered = 0; - for (int i = 0; i < total; i++) + for (int i = 0; i < skills.Count; i++) { - CECSkill skill = player.GetPositiveSkillByIndex(i); + CECSkill skill = skills[i]; if (skill == null) continue; @@ -235,21 +344,19 @@ namespace BrewMonster GameObject cell = Instantiate(skillButtonPrefab, skillGridContainer); - // --- Icon --- string iconName = skill.GetIconFile(); if (!string.IsNullOrEmpty(iconName)) { Sprite icon = uiMan.GetIcon(iconName, EC_GAMEUI_ICONS.ICONS_SKILL); Image cellImage = GetIconImage(cell); - Debug.Log("[SkillTriggerPanel] icon = " + (icon == null) + "cellImage = " + (cellImage == null)); if (cellImage != null && icon != null) cellImage.sprite = icon; } - else{ + else + { Debug.LogWarning("[SkillTriggerPanel] skill.GetIconFile() is empty for skill " + skill.GetSkillID()); } - // --- Label --- Text cellText = cell.GetComponentInChildren(); if (cellText != null) { @@ -259,7 +366,6 @@ namespace BrewMonster : $"{skillName}\nLv{skill.GetSkillLevel()}"; } - // --- Button --- CECSkill captured = skill; Button btn = cell.GetComponentInChildren