Files
test/Assets/PerfectWorld/Scripts/Managers/EC_HPWork.cs
T
Tungdv 001a16cf32 fix: update namespace.
feat: add new logic EC_World.
2025-10-14 18:34:16 +07:00

686 lines
23 KiB
C#

using BrewMonster.Scripts.Player;
using System.Collections.Generic;
namespace BrewMonster.Scripts
{
using WorkList = System.Collections.Generic.List<CECHPWork>;
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 override 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<CECHPWork>(), new List<CECHPWork>(), new List<CECHPWork>() };
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;
}
};
}