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