Change animation logic to using channer act

This commit is contained in:
Tran Hai Nam
2026-05-06 17:46:38 +07:00
parent 96e835d8eb
commit 936dbb7839
4 changed files with 401 additions and 90 deletions
+21 -1
View File
@@ -24,7 +24,7 @@ using BrewMonster.Scripts.ECModel;
namespace BrewMonster
{
public abstract partial class CECPlayer : CECObject
public abstract partial class CECPlayer : CECObject, ITickable
{
[SerializeField] protected Transform parentModel;
[SerializeField] protected TextMeshProUGUI txtName;
@@ -360,6 +360,21 @@ namespace BrewMonster
m_iShape = 0;
m_aEquips = new int[(int)IndexOfIteminEquipmentInventory.SIZE_ALL_EQUIPIVTR];
queueActionEvent = new QueueActionEvent("", null, false, null, 200);
TickInvoker.Instance.RegisterTickable(this);
}
protected virtual void OnDestroy()
{
TickInvoker.Instance.UnregisterTickable(this);
}
public override bool Tick(uint dwDeltaTime)
{
if(m_pPlayerCECModel != null)
{
m_pPlayerCECModel.Tick(dwDeltaTime);
}
return true;
}
/// <summary>This function will get the coressponding model player for the player based on the profession and gender </summary>
@@ -1336,6 +1351,11 @@ namespace BrewMonster
}
return PlayActionWithConfig(iAction, m_PlayerActions[iAction], bRestart, iTransTime, bQueue);
}
const int COMACT_FLAG_MODE_NONE = 0;
const int COMACT_FLAG_MODE_ONCE = 1;
const int COMACT_FLAG_MODE_ONCE_IGNOREGFX = 2;
const int COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX = 3;
private bool PlayActionWithConfig(int iAction, in PLAYER_ACTION actionConfig,
bool bRestart = true, int iTransTime = 200, bool bQueue = false)
+368 -79
View File
@@ -13,6 +13,7 @@ using ECModelHookMap = System.Collections.Generic.Dictionary<string, object>;
using ActQueue = System.Collections.Generic.List<A3DCombActDynData>;
using BrewMonster;
using BrewMonster.Scripts.ECModel;
using Cysharp.Threading.Tasks;
using Unity.VisualScripting.FullSerializer;
public enum ECMScript
{
@@ -54,13 +55,243 @@ public enum ActionChannel
};
public class A3DCombActDynData
{
public A3DCombinedAction combinedAction;
public int nChannel;
public int m_dwUserData;
public bool IsAllActionFinished => m_EventNames.Count == 0;
public List<string> m_EventNames = new List<string>();
protected A3DCombinedAction m_pAct;
protected CECModel m_pECModel;
protected int m_dwTimeSpan;
protected float m_fWeight;
protected int m_nTransTime;
protected int m_dwUserData;
protected bool m_bAbsTrack;
protected bool m_bNoFx;
//ALISTPOSITION m_CurEventPos;
//const ChildActInfo* m_pParentInfo;
//CECModel* m_pParentModel;
protected int m_dwDeltaTime;
protected bool m_bStopPrevAct;
//important
//FxBindBaseList m_ActFxArray;
protected int m_nChannel;
protected int m_dwEventMask;
//ActDynArray m_arrActLoopNum;
protected int m_nCurActIndex;
protected int m_dwDynComActSpan;
protected bool m_bIsInfiniteComAct;
//important
//EventInfoMap m_mapDynAddedInfo;
/// <summary>Attack event tied to this combined action, if any. / 与此组合动作绑定的攻击事件(若有)
/// this is alternative for m_IdCaster to m_IsAttackAct in c++
/// </summary>
public CECAttackEvent ActiveAttackEvent;
public bool m_bResetPSWhenActionStop;
public bool m_bSetSpeedWhenActStart;
public float m_fModelScale;
public List<string> m_ActionNames = new List<string>();
public List<string> m_SFXNames = new List<string>();
public bool IsActionStopped() { return m_ActionNames.Count == 0; }
/// <summary>True when there is no attack or damage has been applied. / 无攻击事件或已造成伤害则为 true</summary>
public bool IsAllEventFinished() { return (ActiveAttackEvent == null || ActiveAttackEvent.m_bDoDamaged); }
/// <summary>Animations finished and attack-event phase finished. / 动画与攻击事件阶段均结束</summary>
public bool IsAllFinished()
{
if(IsActionStopped() && IsAllEventFinished())
{
return true;
}
return false;
}
public A3DCombActDynData(A3DCombinedAction pAct, CECModel pECModel, CECAttackEvent attackEvent)
{
m_pAct = pAct;
m_pECModel = pECModel;
// m_nCurLoop = 0;
// m_nCurActLoop = 0;
m_dwTimeSpan = 0;
m_fWeight = 1.0f;
m_nTransTime = 200;
m_dwUserData = 0;
m_bAbsTrack = false;
m_bNoFx = false;
// m_CurEventPos = 0;
// m_pParentInfo = 0;
// m_pParentModel = 0;
m_bStopPrevAct = false;
m_dwDeltaTime = 0;
m_nChannel = 0;
m_dwEventMask = -1;
//use active attack event instead of idCaster to m_IsAttackAct
ActiveAttackEvent = attackEvent;
// m_idCaster = 0;
// m_idCastTarget = 0;
// m_ptFixed = 0;
// m_SerialId = 0;
// m_IsAttackAct = false;
m_nCurActIndex = -1;
m_dwDynComActSpan = 0;
m_bIsInfiniteComAct = false;
m_bResetPSWhenActionStop = false;
m_bSetSpeedWhenActStart = false;
m_fModelScale = 1.0f;
var actInfoList = pAct.m_ActLst;
// {
// ActInfoList& actInfoList = pAct->m_ActLst;
// ALISTPOSITION pos = actInfoList.GetHeadPosition();
// while (pos)
// {
// PACTION_INFO pAct = actInfoList.GetNext(pos);
// int nDynLoopNum = pAct->CalcLoopNum();
// m_arrActLoopNum.Add(ACTIONDYN_DATA(nDynLoopNum, pAct));
// if (!m_bIsInfiniteComAct && nDynLoopNum < 0) m_bIsInfiniteComAct = true;
// }
// CalcDynComActSpan();
// }
}
/// <param name="triggerVisualAndFx">
/// When true, publishes <see cref="PlayActionEvent"/> for Animancer, tracks <see cref="m_EventNames"/>,
/// and plays combined-action sound FX from data (unless <paramref name="bNoFx"/> suppresses audio).
/// / 为 true 时发布 PlayActionEvent、维护 m_EventNames,并按数据播放组合动作音效(bNoFx 时跳过音效)。
/// </param>
public void Play(int nChannel, float fWeight, int nTransTime, int dwEventMask, bool bRestart, bool bAbsTrack, bool bNoFx,
bool bForceStopPrevious = false, byte channelRank = 0)
{
m_nChannel = nChannel;
m_fWeight = fWeight;
m_nTransTime = nTransTime;
m_dwEventMask = dwEventMask;
m_bAbsTrack = bAbsTrack;
m_bNoFx = bNoFx;
// if (bRestart)
// m_nCurLoop = 0;
m_fModelScale = 1; //Vm_pECModel.GetAllRootBonesScale();
PublishVisual(bForceStopPrevious, channelRank);
if (!m_bNoFx)
TriggerSFxFromEventList();
// Resume();
// UpdateAct(0);
// #ifdef _ANGELICA21
// UpdateEvent(0, 0);
// #endif
}
/// <summary>
/// Notify visual layer and fire combined-action audio using data on this instance.
/// / 通知表现层并根据本实例数据触发组合动作音效。
/// </summary>
void PublishVisual(bool bForceStopPrevious, byte channelRank)
{
if (m_pECModel == null || m_pAct == null)
return;
var actionInfos = m_pAct.m_ActLst;
if (actionInfos != null && actionInfos.Count > 0 && !string.IsNullOrEmpty(actionInfos[0].m_strName))
{
ChannelAct channelAct = m_pECModel.GetChannelAct(m_nChannel);
if (channelAct != null)
{
bool isLoop = m_pAct.m_nLoops == 1;
int ownerId = m_pECModel.GetId();
EventBus.PublishChannel(ownerId, new PlayActionEvent(ref channelAct, actionInfos[0].m_strName, m_nTransTime, bForceStopPrevious, ActiveAttackEvent, isLoop, channelRank));
m_ActionNames.Add(actionInfos[0].m_strName);
for(int i = 1; i < actionInfos.Count; i++)
{
EventBus.PublishChannelClass(ownerId, new QueueActionEvent(ref channelAct, actionInfos[i].m_strName, null, false, null, m_nTransTime, false, isLoop, channelRank));
m_ActionNames.Add(actionInfos[i].m_strName);
}
}
}
}
/// <summary>
/// Sound events embedded in combined action; skip gfx paths. / 组合动作内嵌音效事件;跳过 gfx 路径。
/// </summary>
void TriggerSFxFromEventList()
{
if (m_bNoFx || m_pAct == null)
return;
var eventInfoList = m_pAct.m_EventInfoLst;
if (eventInfoList == null || eventInfoList.Count == 0)
return;
foreach (var eventInfo in eventInfoList)
{
if (eventInfo is FX_BASE_INFO sfx)
{
if (sfx.m_strFilePaths != null && sfx.m_strFilePaths.Count > 0)
{
string soundpath = AFile.NormalizePath(sfx.m_strFilePaths[0], true);
if (soundpath.Contains("gfx"))
continue;
soundpath = soundpath.ToLower();
m_SFXNames.Add(soundpath);
try
{
SFXManager.Instance
.PlaySkillSfxAtPointAsync(soundpath, Vector3.zero).Forget();
}
finally
{
// remove AFTER sound finished
m_SFXNames.Remove(soundpath);
}
}
}
}
}
public void Stop(bool bStopAct, bool bForceStopFx = false )
{
// FlushDamageInfo();
// ClearParentInfo();
// m_nCurLoop = 0;
// m_nCurActLoop = 0;
// RemoveAllActiveFx(bForceStopFx);
// A3DSkinModel* pSkinModel = m_pECModel->GetA3DSkinModel();
// m_pECModel->GetStaticData()->OnScriptEndAction(m_pECModel, m_nChannel, m_pAct->GetName());
// if (IsResetPSWhenActStop())
// {
// m_pECModel->RemoveReplaceShader();
// SetResetPSWhenActStop(false);
// }
// if (m_pAct->GetResetMaterialScale())
// m_pECModel->ResetMaterialScale();
// if (m_pAct->GetStopChildrenAct())
// m_pECModel->StopChildrenAct();
// if (pSkinModel == NULL || !bStopAct)
// return;
// A3DSMActionChannel* pChannel = pSkinModel->GetActionChannel(m_nChannel);
// if (pChannel)
// pChannel->StopAction(m_pAct->GetRank(m_nChannel));
}
public void SetUserData(int dwUserData) { m_dwUserData = dwUserData; }
public void SetTransTime(int nTransTime) { m_nTransTime = nTransTime; }
public void SetStopPrevAct(bool bStopPrevAct) { m_bStopPrevAct = bStopPrevAct; }
public void SetNoFxFlag(bool bNoFx) { m_bNoFx = bNoFx; }
public void SetSpeedWhenActStart(bool bResetSpeed) { m_bSetSpeedWhenActStart = bResetSpeed; }
public bool GetStopPrevAct() { return m_bStopPrevAct; }
public int GetUserData() { return m_dwUserData; }
public int GetTransTime() { return m_nTransTime; }
public bool GetNoFxFlag() { return m_bNoFx; }
public bool IsSetSpeedWhenActStart() { return m_bSetSpeedWhenActStart; }
public A3DCombinedAction GetComAct() { return m_pAct; }
}
public class ChannelActNode
{
@@ -68,22 +299,22 @@ public class ChannelActNode
public A3DCombActDynData m_pActive;
public bool m_pActFlag;
public int m_dwFlagMode;
public ActQueue m_ActQueue;
public ActQueue m_QueuedActs;
public ChannelActNode()
{
m_Rank = 0;
m_pActive = null;
m_pActFlag = false;
m_dwFlagMode = 0;
if(m_ActQueue == null)
if(m_QueuedActs == null)
{
m_ActQueue = new ActQueue();
m_QueuedActs = new ActQueue();
}
m_ActQueue.Clear();
m_QueuedActs.Clear();
}
public void RemoveQueuedActs()
{
m_ActQueue.Clear();
m_QueuedActs.Clear();
}
}
public class ChannelAct
@@ -478,14 +709,27 @@ public class CECModel
private int m_nId = 0;
public GameObject m_pPlayerModel;
private const uint COMACT_FLAG_MODE_NONE = 0;
private const uint COMACT_FLAG_MODE_ONCE_IGNOREGFX = 2;
private const uint COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX = 3;
protected CECModelStaticData m_pMapModel = new CECModelStaticData();
public SkeletonBuilder m_skeletonBuilder;
private Dictionary<string, Transform> m_hookCache = new Dictionary<string, Transform>();
private Dictionary<string, Transform> m_hangerPositionCache = new Dictionary<string, Transform>();
private Dictionary<string, CECModel> m_childModels = new Dictionary<string, CECModel>();
private Transform m_transform;
private bool m_bAbsTrack = false;
public bool InheritParentId() => m_bInheritParentId;
public void SetId(int nId) => m_nId = nId;
public int GetId() => m_nId;
/// <summary>Channel playback container for combined actions. / 组合动作通道容器。</summary>
public ChannelAct GetChannelAct(int nChannel)
{
if (nChannel < 0 || nChannel >= m_ChannelActs.Length)
return null;
return m_ChannelActs[nChannel];
}
//16 is
ChannelAct[] m_ChannelActs = InitChannelActs();
private static ChannelAct[] InitChannelActs()
@@ -783,54 +1027,19 @@ public class CECModel
{
return false;
}
var actionInfos = combinedAction.m_ActLst;
var isLoop = combinedAction.m_nLoops == 1;
var node = m_ChannelActs[nChannel].GetNodeByRank(0);
if (node == null)
var pNode = m_ChannelActs[nChannel].GetNodeByRank(0);
if (pNode == null)
{
node = new ChannelActNode { m_Rank = 0 };
m_ChannelActs[nChannel].m_RankNodes.Add(node);
}
var actData = new A3DCombActDynData
{
combinedAction = combinedAction,
nChannel = nChannel,
m_dwUserData = (int)dwUserData
};
EventBus.PublishChannel(m_nId, new PlayActionEvent(ref m_ChannelActs[nChannel], actionInfos[0].m_strName, nTransTime, bForceStop, attackEvent, isLoop, node.m_Rank));
actData.m_EventNames.Add(actionInfos[0].m_strName);
for(int i = 1; i < actionInfos.Count; i++)
{
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop, node.m_Rank));
actData.m_EventNames.Add(actionInfos[i].m_strName);
pNode = new ChannelActNode { m_Rank = 0 };
m_ChannelActs[nChannel].m_RankNodes.Add(pNode);
}
pNode.m_pActive = new A3DCombActDynData(combinedAction, this, attackEvent);
pNode.m_pActive.SetUserData((int)dwUserData);
pNode.m_pActive.Play(nChannel, fWeight, nTransTime, 0, bRestart, m_bAbsTrack, bNoFx, bForceStop,pNode.m_Rank);
m_bAbsTrack = false;
pNode.m_pActFlag = false;
pNode.m_dwFlagMode = 2;//COMACT_FLAG_MODE_ONCE_IGNOREGFX;
node.m_pActive = actData;
//Todo: should move those event logic to channel act because their control the animation life span.
var eventInfoList = combinedAction.m_EventInfoLst;
if(eventInfoList != null && eventInfoList.Count > 0)
{
foreach(var eventInfo in eventInfoList)
{
//0 is sound event
if (eventInfo is FX_BASE_INFO sfx)
{
if(sfx.m_strFilePaths != null && sfx.m_strFilePaths.Count > 0)
{
string soundpath = AFile.NormalizePath(sfx.m_strFilePaths[0],true);
//we need to determine sfx and gfx. now we dont have logic for this path
if(soundpath.Contains("gfx"))
{
continue;
}
soundpath = soundpath.ToLower();
SFXManager.Instance.PlaySkillSfxAtPointAsync(soundpath, Vector3.zero).Forget();
}
}
}
}
return true;
}
public A3DCombinedAction GetComActByName(string szActName)
@@ -847,28 +1056,28 @@ public class CECModel
{
return false;
}
A3DCombinedAction combinedAction = GetComActByName(szActName);
if(combinedAction == null)
{
A3DCombinedAction pComAct = GetComActByName(szActName);
if (pComAct == null)
return false;
}
var actionInfos = combinedAction.m_ActLst;
var isLoop = combinedAction.m_nLoops == 1;
var node = new ChannelActNode { m_Rank = (byte)m_ChannelActs[nChannel].m_RankNodes.Count};
m_ChannelActs[nChannel].m_RankNodes.Add(node);
var actData = new A3DCombActDynData
{
// combinedAction = combinedAction, // not needed now
nChannel = nChannel,
m_dwUserData = (int)dwUserData
};
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[0].m_strName, null, false, attackEvent, nTransTime, bForceStopPrevAct, isLoop, node.m_Rank));
for(int i = 1; i < actionInfos.Count; i++)
{
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop, node.m_Rank));
actData.m_EventNames.Add(actionInfos[i].m_strName);
}
node.m_pActive = actData;
ChannelAct ca = m_ChannelActs[nChannel];
ChannelActNode pNode = ca.GetNodeByRank(0);
A3DCombActDynData pDynData = new A3DCombActDynData(pComAct, this, attackEvent);
pDynData.SetUserData((int)dwUserData);
pDynData.SetTransTime(nTransTime);
pDynData.SetStopPrevAct(bForceStopPrevAct);
pDynData.SetNoFxFlag(bNoFx);
pDynData.SetSpeedWhenActStart(bResetSpeed);
pNode.m_QueuedActs.Add(pDynData);
// EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[0].m_strName, null, false, attackEvent, nTransTime, bForceStopPrevAct, isLoop, node.m_Rank));
// for(int i = 1; i < actionInfos.Count; i++)
// {
// EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop, node.m_Rank));
// actData.m_EventNames.Add(actionInfos[i].m_strName);
// }
//todo: should add sfx and gfx logic to channel act. currently we dont have logic for queue action. only available for play action.
return true;
}
@@ -880,11 +1089,12 @@ public class CECModel
return false;
}
public int GetCurActionUserData()
public int GetCurActionUserData(int channel = 0)
{
var returnValue = -1;
if (m_ChannelActs[0].GetHighestRankNode() != null)
returnValue = m_ChannelActs[0].GetHighestRankNode().m_pActive.GetUserData();
var nodeCh0 = m_ChannelActs[channel].GetHighestRankNode();
if (nodeCh0 != null)
returnValue = nodeCh0.m_pActive.GetUserData();
return returnValue;
}
public bool QueueAction(CECNPC.INFO iNFO, string szActName, ref bool pNewActFlag, int nTransTime = 200, uint dwUserData = 0, bool bForceStopPrevAct = false, bool bCheckTailDup = false, bool bNoFx = false, bool bResetSpeed = false
@@ -911,6 +1121,85 @@ public class CECModel
AnimationName = animationName;
}
}
public bool Tick(uint dwDeltaTime)
{
UpdateChannelActs(dwDeltaTime);
return true;
}
void UpdateChannelActs(uint dwUpdateTime)
{
if (dwUpdateTime == 0)
return;
for (int i = 0; i < (int)ActionChannel.ACTCHA_MAX; i++)
{
ChannelAct ca = m_ChannelActs[i];
var rankNodes = ca.m_RankNodes;
for (int n = rankNodes.Count - 1; n >= 0; n--)
{
var node = rankNodes[n];
bool bActFinished = false;
if (node.m_dwFlagMode == COMACT_FLAG_MODE_ONCE_IGNOREGFX || node.m_dwFlagMode == COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX)
bActFinished = node.m_pActive.IsActionStopped();
else
bActFinished = node.m_pActive.IsAllFinished();
if (bActFinished)
{
if (node.m_dwFlagMode != COMACT_FLAG_MODE_NONE && node.m_pActFlag)
{
node.m_pActFlag = true;
if (node.m_dwFlagMode != COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX)
node.m_dwFlagMode = (int)COMACT_FLAG_MODE_NONE;
node.m_pActFlag = false;
}
if (node.m_QueuedActs.Count > 0)
{
A3DCombActDynData pNext = node.m_QueuedActs[0];
node.m_QueuedActs.RemoveAt(0);
if (pNext.GetStopPrevAct())
{
node.m_pActive.Stop(true);
//StopChildrenAct();
}
else
node.m_pActive.Stop(false);
// script
//m_pMapModel->OnScriptPlayAction(this, i, pNext->GetComAct()->GetName());
// Èç¹ûQueueActionµÄʱºòÉèÖÃÁËResetSpeed£¬ÔòÕâÀォËÙ¶ÈÉèÖÃÖØÖã¬Ä¬ÈÏÇé¿öϸñê־Ϊfalse
//by2021 ÕâÀï¿ÉÐÞ¸Ä
if (pNext.IsSetSpeedWhenActStart())
SetPlaySpeedByChannel(i, pNext.GetComAct());
node.m_pActive = null;
node.m_pActive = pNext;
node.m_pActive.Play(i, 1f, node.m_pActive.GetTransTime(), 0/**m_EventMasks[i]*/, true, m_bAbsTrack, pNext.GetNoFxFlag());
//pNext.UpdateAct(dwUpdateTime);
m_bAbsTrack = false;
}
else
{
node.m_pActive.Stop(false);
rankNodes.RemoveAt(n);
}
}
// else
// node.m_pActive.UpdateAct(dwUpdateTime);
}
}
}
void SetPlaySpeedByChannel(int nChannel, A3DCombinedAction pComAct)
{
// if (m_nMainChannel == nChannel || 0 == nChannel)
// {
// m_fPlaySpeed = m_fDefPlaySpeed * pComAct.GetPlaySpeed();
// }
}
public void PlayGfx(string szPath, string szHook, float fScale, bool bFadeOut, A3DVECTOR3 vOffset, float fPitch, float fYaw, float fRot, bool bUseECMHook, uint dwFadeOutTime)
{
if (!bFadeOut)
+5 -2
View File
@@ -27,8 +27,11 @@ public class NPCVisual : MonoBehaviour
// BMLogger.LogMono(this, "HoangDev: namedAnimancerIsPlaying == null1: " + animationName);
_currentState = namedAnimancer.TryPlay(animationName, fadeTime);
if (isHit)
{
_currentState.Events.OnEnd = () => SetHitOnEnd(cECAttackEvent);
{
if(_currentState != null)
{
_currentState.Events.OnEnd = () => SetHitOnEnd(cECAttackEvent);
}
}
// if (_currentState != null)
// BMLogger.LogMono(this, "HoangDev: _currentState != null1: " + _currentState.Clip.name);
+7 -8
View File
@@ -59,7 +59,7 @@ namespace BrewMonster
}
previousAnimationName = @event.AnimationName;
InternalPlayAnimation(@event.AnimationName, @event.ITransTime, FadeMode, @event.IsLoop);
ApplyAnimationEndCallbacks(@event.AttackEvent, @event.ChannelAct, @event.Rank);
ApplyAnimationEndCallbacks(@event.AttackEvent, @event.ChannelAct, @event.Rank, @event.AnimationName);
}
public void InitPlayerEventDoneHandler()
{
@@ -228,21 +228,20 @@ namespace BrewMonster
_animationList = _animationQueue.Select(q => q.AnimationName).ToList();
previousAnimationName = animationQueue.AnimationName;
InternalPlayAnimation(animationQueue.AnimationName, animationQueue.ITransTime, FadeMode, animationQueue.IsLoop);
ApplyAnimationEndCallbacks(animationQueue.AttackEvent, animationQueue.ChannelAct, animationQueue.Rank);
ApplyAnimationEndCallbacks(animationQueue.AttackEvent, animationQueue.ChannelAct, animationQueue.Rank, animationQueue.AnimationName);
}
private void ApplyAnimationEndCallbacks(CECAttackEvent attackEvent, ChannelAct channelAct, int rank)
private void ApplyAnimationEndCallbacks(CECAttackEvent attackEvent, ChannelAct channelAct, int rank, string animationName)
{
if (_currentState == null) return;
_currentState.Events.OnEnd = () =>
{
if (attackEvent != null)
attackEvent.m_bSignaled = true;
channelAct.GetNodeByRank((byte)rank).m_pActive.m_EventNames.Remove(_currentAnimationName);
if(channelAct.GetNodeByRank((byte)rank).m_pActive.IsAllActionFinished)
{
//channelAct.RemoveNodeByRank((byte)rank);
}
if (channelAct == null || string.IsNullOrEmpty(animationName))
return;
var node = channelAct.GetNodeByRank((byte)rank);
node?.m_pActive?.m_ActionNames?.Remove(animationName);
};
}
void ApplyDamage()