using System; namespace BrewMonster { /*public class CECPlayerActionController { // Action channels for split-body animation (kept for parity with C++) // 动作通道(保留与C++一致的接口语义) / Channels kept to mirror C++ API public const int ACT_CHANNEL_UPPERBODY = 0; public const int ACT_CHANNEL_LOWERBODY = 1; public const int ACT_CHANNEL_WOUND = 2; private CECPlayer m_pPlayer; private CECModel m_pPlayerModel; private bool m_bSupportCastSkillWhenMove; private CECPlayerActionPlayPolicy m_actionPlayPolicy; private bool m_bSkillAttackActionPlayed; public CECPlayerActionController() { m_pPlayer = null; m_pPlayerModel = null; m_bSupportCastSkillWhenMove = false; m_actionPlayPolicy = null; m_bSkillAttackActionPlayed = false; } ~CECPlayerActionController() { ReleaseActionPlayPolicy(); } public void Bind(CECPlayer player, CECModel playerModel) { if (player == null) { return; } if (player == m_pPlayer && playerModel == m_pPlayerModel) { return; } ReleaseActionPlayPolicy(); m_pPlayer = player; m_pPlayerModel = playerModel; // 是否支持移动中施法(当前C#端未实现,统一设为false) // Support cast-while-move (not implemented in C# port -> false) m_bSupportCastSkillWhenMove = false; if (!m_bSupportCastSkillWhenMove) { // 如果不支持,仍保留“受击”通道逻辑钩子(在C#里留空) // If not supported, keep the hook for wound channel (no-op in C#) } InitializeActionPlayPolicy(); } public bool SupportCastSkillWhenMove() { return m_bSupportCastSkillWhenMove; } public bool CanCombineWithMoveForSkill(int idSkill) { return m_actionPlayPolicy != null && m_actionPlayPolicy.CanCombineWithMoveForSkill(idSkill); } private void InitializeActionPlayPolicy() { // 当前C#只提供默认策略(不拆分上下半身) // Use default policy in this C# port m_actionPlayPolicy = new CECPlayerActionPlayPolicy(m_pPlayer, m_pPlayerModel); } private void ReleaseActionPlayPolicy() { m_actionPlayPolicy = null; } // Build channels (C# no-op, return false to indicate not supported here) // 构建动作通道(C#未实现,返回false) private bool BuildChannelForCastSkillWhenMove() { return false; } public bool PlayNonSkillActionWithName(int iAction, string szActName, bool bRestart = true, int nTransTime = 200, bool bNoFx = false, bool[] pActFlag = null, uint dwFlagMode = 0) { return m_actionPlayPolicy != null && m_actionPlayPolicy.PlayNonSkillActionWithName(iAction, szActName, bRestart, nTransTime, bNoFx, pActFlag, dwFlagMode); } public bool QueueNonSkillActionWithName(int iAction, string szActName, int nTransTime = 200, bool bForceStopPrevAct = false, bool bNoFx = false, bool bResetSpeed = false, bool bResetActFlag = false, bool[] pNewActFlag = null, uint dwNewFlagMode = 0) { return m_actionPlayPolicy != null && m_actionPlayPolicy.QueueNonSkillActionWithName(iAction, szActName, nTransTime, bForceStopPrevAct, bNoFx, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode); } public bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX = false) { if (m_actionPlayPolicy != null && m_actionPlayPolicy.PlaySkillCastActionWithName(idSkill, szActName, bNoFX)) { m_bSkillAttackActionPlayed = false; return true; } return false; } public bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX = false, bool[] pActFlag = null, uint dwFlagMode = 0) { if (m_actionPlayPolicy != null && m_actionPlayPolicy.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, pActFlag, dwFlagMode)) { m_bSkillAttackActionPlayed = true; return true; } return false; } public bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime = 200, bool bNoFX = false, bool bResetSpeed = false, bool bResetActFlag = false, bool[] pNewActFlag = null, uint dwNewFlagMode = 0) { return m_actionPlayPolicy != null && m_actionPlayPolicy.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode); } public bool PlayWoundActionWithName(string szActName) { return m_actionPlayPolicy != null && m_actionPlayPolicy.PlayWoundActionWithName(szActName); } public void ClearComActFlagAllRankNodes(bool bSignalCurrent) { if (m_actionPlayPolicy != null) { m_actionPlayPolicy.ClearComActFlagAllRankNodes(bSignalCurrent); } } public void StopChannelAction() { if (m_actionPlayPolicy != null) { m_actionPlayPolicy.StopChannelAction(); } } public void StopSkillCastAction() { if (m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction() && !m_bSkillAttackActionPlayed) { m_actionPlayPolicy.StopSkillAction(); // LOG kept minimal in C# } } public void StopSkillAttackAction() { if (m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction() && m_bSkillAttackActionPlayed) { m_actionPlayPolicy.StopSkillAction(); // LOG kept minimal in C# } } public bool IsPlayingAction(int iAction) { return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingAction(iAction); } public bool IsPlayingCastingSkillAction() { return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction(); } public bool IsPlayingMoveAction() { return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingMoveAction(); } public int GetLowerBodyAction() { return m_actionPlayPolicy != null ? m_actionPlayPolicy.GetLowerBodyAction() : -1; } }*/ public class CECPlayerActionPlayPolicy { protected readonly CECPlayer m_pPlayer; protected readonly CECModel m_pPlayerModel; // 简单状态记录以支持“是否在施法中”的判断 // Simple state to support IsPlayingCastingSkillAction private bool m_isCastingSkill; public CECPlayerActionPlayPolicy(CECPlayer pPlayer, CECModel pPlayerModel) { m_pPlayer = pPlayer; m_pPlayerModel = pPlayerModel; m_isCastingSkill = false; } public virtual bool CanCombineWithMoveForSkill(int idSkill) { return false; } public CECPlayer GetPlayer() { return m_pPlayer; } public CECModel GetModel() { return m_pPlayerModel; } public bool IsMoving() { return IsPlayingMoveAction() && (m_pPlayer != null && m_pPlayer.IsWorkMoveRunning()); } public static bool IsMoveAction(int action) { return action == (int)PLAYER_ACTION_TYPE.ACT_RUN || action == (int)PLAYER_ACTION_TYPE.ACT_WALK || action == (int)PLAYER_ACTION_TYPE.ACT_FLY || action == (int)PLAYER_ACTION_TYPE.ACT_FLY_SWORD || action == (int)PLAYER_ACTION_TYPE.ACT_SWIM || action == (int)PLAYER_ACTION_TYPE.ACT_SWIM_FOR_MOVESKILL; } public bool IsPlayingCastingSkillAction() { return m_isCastingSkill; } // Non-skill action public virtual bool PlayNonSkillActionWithName(int iAction, string szActName, bool bRestart, int nTransTime, bool bNoFx, CECAttackEvent attackEvent, uint dwFlagMode) { if (m_pPlayer == null || string.IsNullOrEmpty(szActName)) { return false; } int iTransTime = 0; EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new PlayActionEvent(szActName,iTransTime)); return true; } public virtual bool QueueNonSkillActionWithName(int iAction, string szActName, int nTransTime, bool bForceStopPrevAct, bool bNoFx, bool bResetSpeed, bool bResetActFlag, CECAttackEvent attackEvent = null, uint dwNewFlagMode = 0) { // 当前实现:直接播放(队列行为由上层系统处理) // Current: just play, queue behavior handled by upper systems return PlayNonSkillActionWithName(iAction, szActName, false, nTransTime, bNoFx, attackEvent, dwNewFlagMode); } // Skill actions public virtual bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX) { if (m_pPlayer == null || string.IsNullOrEmpty(szActName)) { return false; } if (IsMoving()) { return false; } m_isCastingSkill = true; int iTransTime = 200; EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new PlayActionEvent(szActName,iTransTime)); return true; } public virtual bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX, CECAttackEvent attackEvent, uint dwFlagMode) { if (m_pPlayer == null || string.IsNullOrEmpty(szActName)) { return false; } if (IsMoving()) { return false; } m_isCastingSkill = true; int iTransTime = 200; EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new PlayActionEvent(szActName,iTransTime)); return true; } public virtual bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime, bool bNoFX, bool bResetSpeed, bool bResetActFlag, CECAttackEvent attackEvent, uint dwNewFlagMode) { return PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, attackEvent, dwNewFlagMode); } public virtual bool PlayWoundActionWithName(string szActName) { if (m_pPlayer == null || string.IsNullOrEmpty(szActName)) { return false; } int iTransTime = 0; //EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new PlayActionEvent(szActName,iTransTime)); return true; } public virtual void ClearComActFlagAllRankNodes(bool bSignalCurrent) { if (m_pPlayer != null) { EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new ClearComActFlagAllRankNodesEvent(bSignalCurrent)); } } public virtual void StopChannelAction() { // 在C#端没有底层通道概念,做成清旗标即可 // No channel concept here; clear act flags as a substitute ClearComActFlagAllRankNodes(true); } public virtual void StopSkillAction() { m_isCastingSkill = false; StopChannelAction(); } public virtual bool IsPlayingAction(int iAction) { // C#动画系统由上层驱动,这里不跟踪具体动作,统一返回false // Not tracked here; return false by default return false; } public virtual bool IsPlayingMoveAction() { return false; } public virtual int GetLowerBodyAction() { return -1; } } class CECPlayerActionPlayDefaultPolicy : CECPlayerActionPlayPolicy{ public CECPlayerActionPlayDefaultPolicy(CECPlayer pPlayer, CECModel pPlayerModel): base(pPlayer, pPlayerModel){} public override bool PlayNonSkillActionWithName(int iAction, string szActName, bool bRestart, int nTransTime, bool bNoFx, CECAttackEvent attackEvent, uint dwFlagMode) { ClearComActFlagAllRankNodes(true); bool check = GetModel()!=null && GetModel().PlayActionByName(szActName, 1.0f, bRestart, nTransTime, true, (uint)iAction , bNoFx, attackEvent, dwFlagMode); if (!check) { // BMLogger.LogError($"Fall back to base implementation: {szActName} failed"); //fallback to base implementation(which is non policy based) base.PlayNonSkillActionWithName(iAction, szActName, bRestart, nTransTime, bNoFx, attackEvent, dwFlagMode); } return check; } public override bool QueueNonSkillActionWithName(int iAction, string szActName, int nTransTime, bool bForceStopPrevAct, bool bNoFx, bool bResetSpeed, bool bResetActFlag, CECAttackEvent attackEvent = null, uint dwNewFlagMode = 0) { bool check = GetModel()!=null && GetModel().QueueAction(szActName, nTransTime, (uint)iAction, bForceStopPrevAct, false, bNoFx, bResetSpeed, bResetActFlag, attackEvent, dwNewFlagMode); if (!check) { // BMLogger.LogError($"Fall back to base implementation: {szActName} failed"); //fallback to base implementation(which is non policy based) base.QueueNonSkillActionWithName(iAction, szActName, nTransTime, bForceStopPrevAct, bNoFx, bResetSpeed, bResetActFlag, attackEvent, dwNewFlagMode); } return check; } public override bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX){ if (IsMoving()){ return false; } ClearComActFlagAllRankNodes(true); bool check = GetModel()!=null && GetModel().PlayActionByName(szActName, 1.0f, true, 200, true); if (!check) { // BMLogger.LogError($"Fall back to base implementation: {szActName} failed"); //fallback to base implementation(which is non policy based) base.PlaySkillCastActionWithName(idSkill, szActName, bNoFX); } return check; } public override bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX, CECAttackEvent attackEvent, uint dwFlagMode){ if (IsMoving()){ return false; } //LOG_DEBUG_INFO(AString().Format("PlaySkillAttackActionWithName:%s", szActName)); ClearComActFlagAllRankNodes(true); bool check = GetModel() != null && GetModel().PlayActionByName(szActName, 1.0f, true, 200, true, (uint)PLAYER_ACTION_TYPE.ACT_CASTSKILL, bNoFX, attackEvent, dwFlagMode); if (!check) { //BMLogger.LogError($"Fall back to base implementation: {szActName} failed"); //fallback to base implementation(which is non policy based) base.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, attackEvent, dwFlagMode); } return check; } public override bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime, bool bNoFX, bool bResetSpeed, bool bResetActFlag, CECAttackEvent attackEvent, uint dwNewFlagMode){ //LOG_DEBUG_INFO(AString().Format("QueueSkillAttackActionWithName:%s", szActName)); bool check = GetModel()!=null && GetModel().QueueAction(szActName, nTransTime, (int)PLAYER_ACTION_TYPE.ACT_CASTSKILL, false, false, bNoFX, bResetSpeed, bResetActFlag, attackEvent, dwNewFlagMode); if (!check) { //BMLogger.LogError($"Fall back to base implementation: {szActName} failed"); //fallback to base implementation(which is non policy based) base.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, attackEvent, dwNewFlagMode); } return check; } public override bool PlayWoundActionWithName(string szActName){ // TOdo; add channel support for animation // return GetModel() // && GetModel().PlayActionByName(szActName, (int)ActionChannel.ACTCHA_WOUND, 1, 0, false); return true; // //LOG_DEBUG_INFO(AString().Format("PlayWoundActionWithName:%s", szActName)); } public override void ClearComActFlagAllRankNodes(bool bSignalCurrent){ if (GetModel()!=null){ GetModel().ClearComActFlagAllRankNodes(bSignalCurrent); } } public override void StopChannelAction(){ if (GetModel()!=null){ ClearComActFlagAllRankNodes(true); GetModel().StopChannelAction(0, true); } } public override void StopSkillAction(){ if (GetModel()!=null && IsPlayingCastingSkillAction()){ StopChannelAction(); } } public override bool IsPlayingAction(int iAction){ if (GetModel()!=null){ return (int)GetModel().GetCurActionUserData() == iAction; } return false; } public override bool IsPlayingMoveAction(){ if (GetModel()!=null){ var userData = GetModel().GetCurActionUserData(); return IsMoveAction((int)userData); } return false; } public override int GetLowerBodyAction(){ if (GetModel()!=null){ return GetModel().GetCurActionUserData(); } return -1; } } }