using System.Collections.Generic; using System.Security.Cryptography; using Unity.VisualScripting; using WorkList = System.Collections.Generic.List; public class CECHPWork : CECObjectWork { // Host work ID public static class Host_work_ID { public const int WORK_INVALID = -1, WORK_STAND = 0, // Stand and do nothing WORK_MOVETOPOS = 1, // Move to a destination terrain position WORK_TRACEOBJECT = 2, // Trace specified object (NPC, player etc.) WORK_HACKOBJECT = 3, // Hack specified object (NPC, player etc.) WORK_SPELLOBJECT = 4, // Spell magic on specified object (NPC, player etc.) WORK_USEITEM = 5, // Host use item WORK_DEAD = 6, // Host is dead WORK_FOLLOW = 7, // Follow some one else WORK_FLYOFF = 8, // Fly off WORK_FREEFALL = 9, // Free fall WORK_SIT = 10, // Sit WORK_PICKUP = 11, // Pickup item WORK_CONCENTRATE = 12, // All concentrate work WORK_REVIVE = 13, // Revive WORK_FLASHMOVE = 14, // Flash move WORK_BEBOUND = 15, // Be bound by buddy WORK_PASSIVEMOVE = 16, // Passive movement (knock back / pull) WORK_CONGREGATE = 17, // Congregate reply WORK_SKILLSTATEACT = 18, // skill buff action WORK_FORCENAVIGATEMOVE = 19, // force navigate move NUM_WORK = 20; } protected static class Work_mask { public const uint MASK_STAND = 0x0001, MASK_MOVETOPOS = 0x0002, MASK_TRACEOBJECT = 0x0004, MASK_HACKOBJECT = 0x0008, MASK_SPELLOBJECT = 0x0010, MASK_USEITEM = 0x0020, MASK_DEAD = 0x0040, MASK_FOLLOW = 0x0080, MASK_FLYOFF = 0x0100, MASK_FREEFALL = 0x0200, MASK_SIT = 0x0400, MASK_PICKUP = 0x0800, MASK_CONCENTRATE = 0x1000, MASK_REVIVE = 0x2000, MASK_FLASHMOVE = 0x4000, MASK_BEBOUND = 0x8000, MASK_CONGREGATE = 0x10000, MASK_SKILLSTATEACT = 0x20000, MASK_FORCENAVIGATE = 0x40000; public const uint MASK_ALLWORK = 0xffffffff; } protected CECHPWorkMan m_pWorkMan; // Work manager protected CECHostPlayer m_pHost; // Host player object public CECHPWork(int iWorkID, CECHPWorkMan pWorkMan) : base(iWorkID) { m_pWorkMan = pWorkMan; m_pHost = pWorkMan.GetHostPlayer(); } // Operations // Override from CECObjectWork public virtual void Cancel() { } // This work is do player moving ? public virtual bool IsMoving() { return false; } // Copy work data public virtual bool CopyData(CECHPWork pWork) { m_bFinished = pWork.m_bFinished; m_bFirstTick = pWork.m_bFirstTick; return true; } public string GetWorkName() { return GetWorkName(GetWorkID()); } public static uint GetWorkMask(int iWorkID) { if (!Validate(iWorkID)) { return 0; } uint[] l_workMask = new uint[]{ Work_mask.MASK_STAND, Work_mask.MASK_MOVETOPOS, Work_mask.MASK_TRACEOBJECT, Work_mask.MASK_HACKOBJECT, Work_mask.MASK_SPELLOBJECT, Work_mask.MASK_USEITEM, Work_mask.MASK_DEAD, Work_mask.MASK_FOLLOW, Work_mask.MASK_FLYOFF, Work_mask.MASK_FREEFALL, Work_mask.MASK_SIT, Work_mask.MASK_PICKUP, Work_mask.MASK_CONCENTRATE, Work_mask.MASK_REVIVE, Work_mask.MASK_FLASHMOVE, Work_mask.MASK_BEBOUND, Work_mask.MASK_CONGREGATE, Work_mask.MASK_SKILLSTATEACT, Work_mask.MASK_FORCENAVIGATE, }; return l_workMask[iWorkID]; } public static bool Validate(int iWorkID) { return iWorkID >= 0 && iWorkID < Host_work_ID.NUM_WORK; } public static string GetWorkName(int iWorkID) { string[] l_WorkName = new string[Host_work_ID.NUM_WORK] { "WORK_STAND", "WORK_MOVETOPOS", "WORK_TRACEOBJECT", "WORK_HACKOBJECT", "WORK_SPELLOBJECT", "WORK_USEITEM", "WORK_DEAD", "WORK_FOLLOW", "WORK_FLYOFF", "WORK_FREEFALL", "WORK_SIT", "WORK_PICKUP", "WORK_CONCENTRATE", "WORK_REVIVE", "WORK_FLASHMOVE", "WORK_BEBOUND", "WORK_PASSIVEMOVE", "WORK_CONGREGATE", "WORK_SKILLSTATEACT", "WORK_FORCENAVIGATEMOVE" }; if (Validate(iWorkID)) { return l_WorkName[iWorkID]; } else if (iWorkID == Host_work_ID.WORK_INVALID) { return "WORK_INVALID"; } else { return "Unknown"; } } } /////////////////////////////////////////////////////////////////////////// // // Class CECHPWorkMan // /////////////////////////////////////////////////////////////////////////// public class CECHPWorkMan { // Work priority public static class Work_priority { public const int PRIORITY_0 = 0, PRIORITY_1 = 1, PRIORITY_2 = 2, NUM_PRIORITY = 3; }; // Delayed work info. public struct DELAYWORK { public int iPriority; public CECHPWork pWork; } private CECHostPlayer m_pHost; private WorkList[] m_WorkStack = new WorkList[Work_priority.NUM_PRIORITY] { new List(), new List(), new List() }; private int m_iCurPriority; private DELAYWORK m_Delayed; private CECHPWorkPostTickCommand m_pPostTickCommand; public CECHPWorkMan(CECHostPlayer pHost) { m_pHost = pHost; m_iCurPriority = -1; m_Delayed = new DELAYWORK { iPriority = 0, pWork = null }; m_pPostTickCommand = null; } public CECHPWork GetRunningWork(int iWorkID) { CECHPWork result = null; if (ValidatePriority(m_iCurPriority)) { WorkList workList = m_WorkStack[m_iCurPriority]; for (int i = 0; i < workList.Count; ++i) { if (iWorkID == workList[i].GetWorkID()) { result = workList[i]; break; } } } return result; } public CECHPWork GetWork(int iWorkID, int iPriority = Work_priority.PRIORITY_1, bool bIncludeDelayedWork = false) { CECHPWorkGeneralMatcher cECHPWork = new CECHPWorkGeneralMatcher(iWorkID, iPriority, bIncludeDelayedWork); return GetWork(cECHPWork); } public CECHPWork GetWork(CECHPWorkMatcher matcher) { CECHPWork result = null; for (int i = (Work_priority.NUM_PRIORITY - 1); i >= 0; --i) { WorkList workList = m_WorkStack[i]; if (workList != null) { for (int j = 0; j < workList.Count; ++j) { CECHPWork pWork = workList[j]; if (matcher.Match(pWork, i, false)) { result = pWork; break; } } } } if (result == null && GetDelayedWork() != null && matcher.Match(m_Delayed.pWork, m_Delayed.iPriority, true)) { result = GetDelayedWork(); } return result; } bool InternallyStartWork(int iPriority, CECHPWork pWork) { bool bStarted = false; if (CanRunSimultaneouslyWithCurrentWork(iPriority, pWork)) { WorkList workList = m_WorkStack[iPriority]; workList.Add(pWork); bStarted = true; //LOG_DEBUG_INFO(AString().Format("CECHPWork::%s started simultaneously, priority=%d", pWork->GetWorkName(), iPriority)); } else { if (pWork.GetWorkID() == CECHPWork.Host_work_ID.WORK_DEAD) { for (int i = iPriority; i < Work_priority.NUM_PRIORITY; i++) { FinishWorkAtPriority(i); } ClearDelayedWork(); WorkList workList = m_WorkStack[iPriority]; workList.Add(pWork); m_iCurPriority = iPriority; bStarted = true; } else { bool shouldStart = (iPriority >= m_iCurPriority); FinishWorkAtPriority(iPriority); WorkList workList = m_WorkStack[iPriority]; workList.Add(pWork); if (shouldStart) { if (iPriority > m_iCurPriority) { CancelWorkAtPriority(m_iCurPriority); } m_iCurPriority = iPriority; bStarted = true; } } //if (bStarted) //{ // LOG_DEBUG_INFO(AString().Format("CECHPWork::%s started, priority=%d", pWork->GetWorkName(), iPriority)); //} //else //{ // LOG_DEBUG_INFO(AString().Format("CECHPWork::%s add to priority queue %d", pWork->GetWorkName(), iPriority)); //} } return bStarted; } bool CanRunSimultaneouslyWithCurrentWork(int iPriority, CECHPWork pWork) { if (!ValidatePriority(iPriority) || iPriority != m_iCurPriority) { return false; } WorkList workList = m_WorkStack[iPriority]; if (workList == null || workList.Count == 0) { return false; } foreach (var work in workList) { if (!CanRunSimultaneously(work, pWork)) { return false; } } return true; } bool CanRunSimultaneously(CECHPWork pWork1, CECHPWork pWork2) { if (pWork1.GetWorkID() == CECHPWork.Host_work_ID.WORK_MOVETOPOS && pWork2.GetWorkID() == CECHPWork.Host_work_ID.WORK_SPELLOBJECT) { return CanSpellWhileMoving(pWork2 as CECHPWorkSpell); } if (pWork2.GetWorkID() == CECHPWork.Host_work_ID.WORK_MOVETOPOS && pWork1.GetWorkID() == CECHPWork.Host_work_ID.WORK_SPELLOBJECT) { return CanSpellWhileMoving(pWork1 as CECHPWorkSpell); } return false; } bool CanSpellWhileMoving(CECHPWorkSpell pWorkSpell) { //return pWorkSpell.GetSkill() // && CECCastSkillWhenMove::Instance().IsSkillSupported(pWorkSpell->GetSkill()->GetSkillID(), m_pHost); return false; } void StartAwaitingWorks() { if (ValidatePriority(m_iCurPriority)) { for (--m_iCurPriority; m_iCurPriority >= 0; --m_iCurPriority) { WorkList workList = m_WorkStack[m_iCurPriority]; if (workList == null || workList.Count == 0) { continue; } foreach (var work in workList) { work.OnWorkShift(); //LOG_DEBUG_INFO(AString().Format("CECHPWork::%s started by decrease priority, priority=%d", workList[j]->GetWorkName(), m_iCurPriority)); } break; } } StartDelayedWork(); } void FinishWorkAtPriority(int iPriority) { if (!ValidatePriority(iPriority)) { return; } WorkList workList = m_WorkStack[iPriority]; while ((workList != null && workList.Count > 0)) { KillWork(iPriority, 0); } if (m_iCurPriority == iPriority) { m_iCurPriority = -1; } } void KillWork(int iPriority, int index) { if (!ValidatePriority(iPriority)) { return; } WorkList workList = m_WorkStack[iPriority]; if (index < 0 || index >= workList.Count) { return; } CECHPWork pWork = workList[index]; KillWork(pWork); //LOG_DEBUG_INFO(AString().Format("CECHPWork::%s priority=%d killed", pWork->GetWorkName(), iPriority)); //delete pWork; workList.RemoveAt(index); } void KillWork(CECHPWork pWork) { if (pWork == null) { return; } if (pWork.GetWorkID() == CECHPWork.Host_work_ID.WORK_MOVETOPOS) { CECHPWorkMove pWorkMove = pWork as CECHPWorkMove; if (pWorkMove != null) { if (pWorkMove.GetAutoMove()) { //pWorkMove.Finish(); } else { pWorkMove.Cancel(); } } } else { pWork.Cancel(); } } public void CancelWork(CECHPWork pWork) { } public void CancelWorkAtPriority(int iPriority) { } public bool DelayWork(int iPriority, CECHPWork pWork) { return false; } public void StartDelayedWork() { } public void ClearDelayedWork() { } public CECHPWork GetDelayedWork() { return m_Delayed.pWork; } public bool ValidatePriority(int iPriority) { return iPriority >= 0 && iPriority < Work_priority.NUM_PRIORITY; } public bool StartWork(int iPriority, CECHPWork pWork, bool bNoDelay = false) { if (pWork == null) { return false; } if (!ValidatePriority(iPriority)) { return false; } //if (pWork.GetWorkID() == CECHPWork.Host_work_ID.WORK_TRACEOBJECT) //{ // if (g_pGame->GetGameRun()->GetHostInputFilter()->IsMoveUsagePressed()) // { // CECHPWorkTrace pWorkTrace = pWork as CECHPWorkTrace; // if (!pWorkTrace.CanTouch()) // { // 2014-8-16 当还在通过键盘操纵移动时、有条件忽略 CECHPWorkTrace, // //delete pWorkTrace; // 否则会因 CECHPWorkTrace 中临时转向目标位置、而后又被键盘操纵调整移动方向导致方向瞬间抖动 // return false; // 当 CECHPWorkTrace 中目标可立即接触时,不忽略 CECHPWorkTrace,以实现键盘控制移动中、对某怪应用技能时,立刻转向怪施放技能 // } // } //} if (!bNoDelay && DelayWork(iPriority, pWork)) { return true; } return InternallyStartWork(iPriority, pWork); } public bool StartWork_p0(CECHPWork pWork, bool bNoDelay = false) { return StartWork(Work_priority.PRIORITY_0, pWork, bNoDelay); } public bool StartWork_p1(CECHPWork pWork, bool bNoDelay = false) { return StartWork(Work_priority.PRIORITY_1, pWork, bNoDelay); } public bool StartWork_p2(CECHPWork pWork, bool bNoDelay = false) { return StartWork(Work_priority.PRIORITY_2, pWork, bNoDelay); } public CECHostPlayer GetHostPlayer() { return m_pHost; } public CECHPWork CreateWork(int idWork) { CECHPWork pWork = null; switch (idWork) { //case CECHPWork.Host_work_ID.WORK_STAND: pWork = new CECHPWorkStand(this); break; case CECHPWork.Host_work_ID.WORK_MOVETOPOS: pWork = new CECHPWorkMove(this); break; case CECHPWork.Host_work_ID.WORK_TRACEOBJECT: pWork = new CECHPWorkTrace(this); break; case CECHPWork.Host_work_ID.WORK_HACKOBJECT: pWork = new CECHPWorkMelee(this); break; case CECHPWork.Host_work_ID.WORK_SPELLOBJECT: pWork = new CECHPWorkSpell(this); break; //case CECHPWork.Host_work_ID.WORK_USEITEM: pWork = new CECHPWorkUse(this); break; //case CECHPWork.Host_work_ID.WORK_DEAD: pWork = new CECHPWorkDead(this); break; //case CECHPWork.Host_work_ID.WORK_FOLLOW: pWork = new CECHPWorkFollow(this); break; //case CECHPWork.Host_work_ID.WORK_FLYOFF: pWork = new CECHPWorkFly(this); break; //case CECHPWork.Host_work_ID.WORK_FREEFALL: pWork = new CECHPWorkFall(this); break; //case CECHPWork.Host_work_ID.WORK_SIT: pWork = new CECHPWorkSit(this); break; //case CECHPWork.Host_work_ID.WORK_PICKUP: pWork = new CECHPWorkPick(this); break; //case CECHPWork.Host_work_ID.WORK_CONCENTRATE: pWork = new CECHPWorkConcentrate(this); break; //case CECHPWork.Host_work_ID.WORK_REVIVE: pWork = new CECHPWorkRevive(this); break; //case CECHPWork.Host_work_ID.WORK_FLASHMOVE: pWork = new CECHPWorkFMove(this); break; //case CECHPWork.Host_work_ID.WORK_BEBOUND: pWork = new CECHPWorkBeBound(this); break; //case CECHPWork.Host_work_ID.WORK_PASSIVEMOVE: pWork = new CECHPWorkPassiveMove(this); break; //case CECHPWork.Host_work_ID.WORK_CONGREGATE: pWork = new CECHPWorkCongregate(this); break; //case CECHPWork.Host_work_ID.WORK_SKILLSTATEACT: pWork = new CECHPWorkSkillStateAction(this); break; //case CECHPWork.Host_work_ID.WORK_FORCENAVIGATEMOVE: pWork = new CECHPWorkNavigate(this); break; default: return null; } return pWork; } public bool CanStartWork(int iWorkID, int iPriority = CECHPWorkMan.Work_priority.PRIORITY_1) { if (!ValidatePriority(iPriority)) { return false; } if (GetWork(iWorkID) != null) { return false; } if (!HasWorkOnPriority(iPriority)) { return true; } WorkList workList = m_WorkStack[iPriority]; if (workList != null) { for (int i = 0; i < workList.Count; ++i) { if (!workList[i].CanTransferTo(CECHPWork.GetWorkMask(iWorkID))) { return false; } } } return true; } bool HasWorkOnPriority(int iPriority) { return ValidatePriority(iPriority) && m_WorkStack[iPriority] != null && m_WorkStack[iPriority].Count != 0; } public void SetPostTickCommand(CECHPWorkPostTickCommand command) { m_pPostTickCommand = command; } public bool HasWorkRunningOnPriority(int iPriority) { return HasWorkOnPriority(iPriority); } bool IsAnyWorkRunning() { return HasWorkRunningOnPriority(m_iCurPriority); } public void Tick(float dwDeltaTime) { if (!IsAnyWorkRunning()) { return; } WorkList workList = m_WorkStack[m_iCurPriority]; for (int i = 0; i < workList.Count;) { CECHPWork pWork = workList[i]; SetPostTickCommand(null); pWork.Tick(dwDeltaTime); if (m_pPostTickCommand == null) { if (!pWork.IsFinished()) { ++i; continue; } KillWork(m_iCurPriority, i); } else { m_pPostTickCommand.Run(this); SetPostTickCommand(null); break; // 不确定 m_pPostTickCommand 执行什么内容,此处跳出 } } if (workList.Count == 0) { StartAwaitingWorks(); } } } public abstract class CECHPWorkPostTickCommand { public abstract bool Run(CECHPWorkMan pWorkMan); }; public abstract class CECHPWorkMatcher { public abstract bool Match(CECHPWork pWork, int priority, bool isDelayWork); }; public class CECHPWorkGeneralMatcher : CECHPWorkMatcher { int m_workID; int m_priority; bool m_matchDelayedWork; public override bool Match(CECHPWork pWork, int priority, bool isDelayWork) { return pWork != null && pWork.GetWorkID() == m_workID && priority == m_priority && isDelayWork == m_matchDelayedWork; } public CECHPWorkGeneralMatcher(int workID, int priority, bool bIncludeDelayedWork) { m_workID = workID; m_priority = priority; m_matchDelayedWork = bIncludeDelayedWork; } } public class CECHPWorkPostTickRunWorkCommand : CECHPWorkPostTickCommand { CECHPWork m_pWork; int m_iPriority; bool m_bNoDelay; bool m_bShouldTick; uint m_dwTickTime; // Constructor public CECHPWorkPostTickRunWorkCommand( CECHPWork pWork, bool bNoDelay = false, int iPriority = CECHPWorkMan.Work_priority.PRIORITY_1, bool bShouldTick = false, uint dwTickTime = 0) { m_pWork = pWork; m_bNoDelay = bNoDelay; m_iPriority = iPriority; m_bShouldTick = bShouldTick; m_dwTickTime = dwTickTime; } public override bool Run(CECHPWorkMan pWorkMan) { if (m_pWork == null || pWorkMan == null) { return false; } if (!pWorkMan.StartWork(m_iPriority, m_pWork, m_bNoDelay)) { m_pWork = null; return false; } if (m_bShouldTick) { m_pWork.Tick(m_dwTickTime); } m_pWork = null; return true; } };