diff --git a/amxmodx/CTask.cpp b/amxmodx/CTask.cpp index e5f8aee0..2cd33de9 100755 --- a/amxmodx/CTask.cpp +++ b/amxmodx/CTask.cpp @@ -31,9 +31,6 @@ #include "amxmodx.h" #include "CTask.h" -#include "sh_stack.h" - -CStack *g_FreeTasks; /*********************** CTask ***********************/ @@ -50,6 +47,7 @@ CPluginMngr::CPlugin *CTaskMngr::CTask::getPlugin() const void CTaskMngr::CTask::set(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, cell iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat, float fCurrentTime) { clear(); + m_bFree = false; m_pPlugin = pPlugin; m_iFunc = iFunc; @@ -67,61 +65,56 @@ void CTaskMngr::CTask::set(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, m_iRepeat = iRepeat; } - type = 0; - if (iFlags & 4) - type = 1; - if (iFlags & 8) - type = 2; + m_bAfterStart = (iFlags & 4) ? true : false; + m_bBeforeEnd = (iFlags & 8) ? true : false; m_fNextExecTime = fCurrentTime + m_fBase; if (iParamsLen) { m_iParamLen = iParamsLen + 1; - if (m_ParamSize < m_iParamLen) - { - m_ParamSize = m_iParamLen; - cell *temp = new cell[m_ParamSize]; - if (m_pParams != NULL) - delete [] m_pParams; - m_pParams = temp; - } - cell *dest = m_pParams; -#if defined WIN32 && !defined __GNUC__ - __asm - { - push esi; - push edi; - push ecx; - mov esi, pParams; - mov edi, dest; - mov ecx, iParamsLen; - rep movsd; - pop esi; - pop edi; - pop ecx; - }; -#else - memcpy(m_pParams, pParams, sizeof(cell) * iParamsLen); -#endif + m_pParams = new cell[m_iParamLen]; + memcpy(m_pParams, pParams, sizeof(cell)*iParamsLen); m_pParams[iParamsLen] = 0; } else { m_iParamLen = 0; + m_pParams = NULL; } } void CTaskMngr::CTask::clear() { + m_bFree = true; + if (m_iFunc >= 0) { unregisterSPForward(m_iFunc); m_iFunc = -1; } + if (m_pParams) + { + delete [] m_pParams; + m_pParams = NULL; + } + + m_pPlugin = NULL; m_iId = 0; + m_fBase = 0.0f; + + m_iRepeat = 0; + m_bLoop = false; + m_bAfterStart = false; + m_bBeforeEnd = false; + m_fNextExecTime = 0.0f; } +bool CTaskMngr::CTask::isFree() const +{ + return m_bFree; +} + void CTaskMngr::CTask::changeBase(float fNewBase) { m_fBase = fNewBase; @@ -132,29 +125,24 @@ void CTaskMngr::CTask::resetNextExecTime(float fCurrentTime) m_fNextExecTime = fCurrentTime + m_fBase; } -int CTaskMngr::CTask::executeIfRequired(float fCurrentTime, float fTimeLimit, float fTimeLeft) +void CTaskMngr::CTask::executeIfRequired(float fCurrentTime, float fTimeLimit, float fTimeLeft) { bool execute = false; bool done = false; - - switch (type) + + if (m_bAfterStart) { - case 1: - { - if (fCurrentTime - fTimeLeft + 1.0f >= m_fBase) - execute = true; - break; - } - case 2: - { - if (fTimeLimit != 0.0f && (fTimeLeft + fTimeLimit * 60.0f) - fCurrentTime - 1.0f <= m_fBase) - execute = true; - break; - } - default: - { - execute = (m_fNextExecTime <= fCurrentTime) ? true : false; - } + if (fCurrentTime - fTimeLeft + 1.0f >= m_fBase) + execute = true; + } + else if (m_bBeforeEnd) + { + if (fTimeLimit != 0.0f && (fTimeLeft + fTimeLimit * 60.0f) - fCurrentTime - 1.0f <= m_fBase) + execute = true; + } + else if (m_fNextExecTime <= fCurrentTime) + { + execute = true; } if (execute) @@ -170,6 +158,9 @@ int CTaskMngr::CTask::executeIfRequired(float fCurrentTime, float fTimeLimit, fl executeForwards(m_iFunc, m_iId); } } + + if (isFree()) + return; // set new exec time OR remove the task if needed if (m_bLoop) @@ -180,15 +171,19 @@ int CTaskMngr::CTask::executeIfRequired(float fCurrentTime, float fTimeLimit, fl done = true; } - if (!done) + if (done) + { + clear(); + } else { m_fNextExecTime += m_fBase; + } } - - return (execute ? (done ? Task_Done : Task_Rel) : Task_Nothing); } CTaskMngr::CTask::CTask() { + m_bFree = true; + m_pPlugin = NULL; m_iFunc = -1; m_iId = 0; @@ -196,24 +191,18 @@ CTaskMngr::CTask::CTask() m_iRepeat = 0; m_bLoop = false; - type = 0; + m_bAfterStart = false; + m_bBeforeEnd = false; m_fNextExecTime = 0.0f; m_iParamLen = 0; - m_ParamSize = 0; m_pParams = NULL; } CTaskMngr::CTask::~CTask() { clear(); - - if (m_pParams) - { - delete [] m_pParams; - m_pParams = NULL; - } } /*********************** CTaskMngr ***********************/ @@ -223,16 +212,11 @@ CTaskMngr::CTaskMngr() m_pTmr_CurrentTime = NULL; m_pTmr_TimeLimit = NULL; m_pTmr_TimeLeft = NULL; - - g_FreeTasks = new CStack(); } CTaskMngr::~CTaskMngr() { clear(); - if (g_FreeTasks) - delete g_FreeTasks; - g_FreeTasks = NULL; } void CTaskMngr::registerTimers(float *pCurrentTime, float *pTimeLimit, float *pTimeLeft) @@ -245,349 +229,73 @@ void CTaskMngr::registerTimers(float *pCurrentTime, float *pTimeLimit, float *pT void CTaskMngr::registerTask(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, cell iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat) { // first, search for free tasks - CTask *pTmp = NULL; - if (!g_FreeTasks->empty()) + TaskListIter iter = m_Tasks.find(CTaskDescriptor(0, NULL, true)); + + if (iter) { // found: reuse it - pTmp = g_FreeTasks->front(); - g_FreeTasks->pop(); - pTmp->set(pPlugin, iFunc, iFlags, iId, fBase, iParamsLen, pParams, iRepeat, *m_pTmr_CurrentTime); + iter->set(pPlugin, iFunc, iFlags, iId, fBase, iParamsLen, pParams, iRepeat, *m_pTmr_CurrentTime); } else { // not found: make a new one - pTmp = new CTask; + CTask *pTmp = new CTask; + + if (!pTmp) + return; + pTmp->set(pPlugin, iFunc, iFlags, iId, fBase, iParamsLen, pParams, iRepeat, *m_pTmr_CurrentTime); + m_Tasks.put(pTmp); } - - insertTask(pTmp); -} - -float CTaskMngr::CTask::nextThink() -{ - float _next = 0.0f; - /*switch (type) - { - case 0: - {*/ - _next = m_fNextExecTime - g_tasksMngr.CurrentTime(); - if (_next < 0.0f) - _next = 0.0f; - /*break; - } - case 1: - { - _next = m_fBase - (g_tasksMngr.CurrentTime() - g_tasksMngr.TimeLeft() + 1.0f); - if (_next < 0.0f) - _next = 0.0f; - break; - } - case 2: - { - if (g_tasksMngr.TimeLimit() == 0.0f) - { - _next = INFINITE; - } else { - _next = ((g_tasksMngr.TimeLeft() + g_tasksMngr.TimeLimit() * 60.0f) - g_tasksMngr.CurrentTime() - 1.0f) - m_fBase; - if (_next < 0.0f) - _next = 0.0f; - } - break; - } - }*/ - return _next; } int CTaskMngr::removeTasks(int iId, AMX *pAmx) { - CTask *pTask = first; - CTask *pTemp; - int num = 0; - while (pTask) + CTaskDescriptor descriptor(iId, pAmx); + TaskListIter iter = m_Tasks.find(descriptor); + int i = 0; + + while (iter) { - pTemp = pTask->next; - if ((!pAmx || (pTask->m_pPlugin->getAMX() == pAmx)) - && (pTask->m_iId == iId)) - { - removeTask(pTask); - pTask->clear(); - delete pTask; - num++; - } - pTask = pTemp; + iter->clear(); + ++i; + iter = m_Tasks.find(++iter, descriptor); } - - return num; + + return i; } int CTaskMngr::changeTasks(int iId, AMX *pAmx, float fNewBase) { - CTask *pTask = first; - int num = 0; - while (pTask) + CTaskDescriptor descriptor(iId, pAmx); + TaskListIter iter = m_Tasks.find(descriptor); + int i = 0; + + while (iter) { - if ((!pAmx || (pTask->m_pPlugin->getAMX() == pAmx)) - && (pTask->m_iId == iId)) - { - pTask->changeBase(fNewBase); - pTask->resetNextExecTime(*m_pTmr_CurrentTime); - num++; - } - pTask = pTask->next; + iter->changeBase(fNewBase); + iter->resetNextExecTime(*m_pTmr_CurrentTime); + ++i; + iter = m_Tasks.find(++iter, descriptor); } - - return num; + + return i; } bool CTaskMngr::taskExists(int iId, AMX *pAmx) { - CTask *pTask = first; - while (pTask) - { - if ((!pAmx || (pTask->m_pPlugin->getAMX() == pAmx)) - && (pTask->m_iId == iId)) - { - return true; - } - pTask = pTask->next; - } - - return false; + return m_Tasks.find(CTaskDescriptor(iId, pAmx)); } -static int run_tasks = 0; - void CTaskMngr::startFrame() { - CTask *pTask = first; - CTask *pNext; - float time_cur = *m_pTmr_CurrentTime; - float time_left = *m_pTmr_TimeLeft; - float time_limit = *m_pTmr_TimeLimit; - int val; - while (pTask) + for (TaskListIter iter = m_Tasks.begin(); iter; ++iter) { - pNext = pTask->next; - if ( (val=pTask->executeIfRequired(time_cur, time_limit, time_left)) == Task_Nothing ) - { - //we're DONE - break; - } else { - run_tasks++; - removeTask(pTask); - if (val == Task_Rel) - { - //relocate task - insertTask(pTask); - } else { - //do this for now to catch list/tree errors - delete pTask; - } - } - pTask = pNext; - } -} - -static int removed_tasks = 0; - -void CTaskMngr::removeTask(CTask *pTask) -{ - removed_tasks++; - //first, remove us from the linked list. - if (pTask->prev) - pTask->prev->next = pTask->next; - if (pTask->next) - pTask->next->prev = pTask->prev; - if (pTask == first) - first = pTask->next; - - //case 1: no right child - if (pTask->child[AVL_RIGHT] == NULL) - { - if (pTask->parent) - { - //link our parent's child to our child, eliminating us - if (pTask->parent->child[AVL_LEFT] == pTask) - pTask->parent->child[AVL_LEFT] = pTask->child[AVL_LEFT]; - else - pTask->parent->child[AVL_RIGHT] = pTask->child[AVL_LEFT]; - } else { - //the only node with no parent is root - root = pTask->child[AVL_LEFT]; - } - //if we have a left child, correct its parent - if (pTask->child[AVL_LEFT]) - pTask->child[AVL_LEFT]->parent = pTask->parent; - } else { - CTask *pSwap = NULL; - if (pTask->child[AVL_LEFT] == NULL) - { - //case 2: we have no left child, it's safe to just rebind - if (pTask->parent) - { - if (pTask->parent->child[AVL_LEFT] == pTask) - pTask->parent->child[AVL_LEFT] = pTask->child[AVL_RIGHT]; - else - pTask->parent->child[AVL_RIGHT] = pTask->child[AVL_RIGHT]; - } else { - //the only node with no parent is root - root = pTask->child[AVL_RIGHT]; - } - //if we have a left child, correct its parent - //we have a right channel because of the case we're in. - pTask->child[AVL_RIGHT]->parent = pTask->parent; - } else { - //case 3: we have a right child, but it has no left child. - if (pTask->child[AVL_RIGHT]->child[AVL_LEFT] == NULL) - { - pSwap = pTask->child[AVL_RIGHT]; - if (pTask->parent) - { - //link our parent's child to our child, eliminating us - if (pTask->parent->child[AVL_LEFT] == pTask) - pTask->parent->child[AVL_LEFT] = pSwap; - else - pTask->parent->child[AVL_RIGHT] = pSwap; - } else { - root = pSwap; - } - //set our child's parent to our parent - pSwap->parent = pTask->parent; - //if we have a left child, link it up to its new parent - if (pTask->child[AVL_LEFT]) - pTask->child[AVL_LEFT]->parent = pSwap; - //Set our child's left to whatever our left is - pSwap->child[AVL_LEFT] = pTask->child[AVL_LEFT]; - } else { - //case 4: we have a right child with at least a left child. - //climb down the list to find the BIGGEST value that is - // SMALLER than our node. - pSwap = pTask->child[AVL_LEFT]; - while (pSwap->child[AVL_RIGHT]) - pSwap = pSwap->child[AVL_RIGHT]; - if (pTask->parent) - { - if (pTask->parent->child[AVL_LEFT] == pTask) - pTask->parent->child[AVL_LEFT] = pSwap; - else - pTask->parent->child[AVL_RIGHT] = pSwap; - } else { - root = pSwap; - } - //the left child is guaranteed to not have another left child. - //for this reason we can perform a swap like above ones. - //however, there are more precautions. - //unlink our swapped node. it's gone from that position. - if (pSwap->parent) - pSwap->parent->child[AVL_RIGHT] = NULL; - //link swap to new parent - pSwap->parent = pTask->parent; - //set our children to have the swap as the parent - pTask->child[AVL_RIGHT]->parent = pSwap; - if (pTask->child[AVL_LEFT]) - pTask->child[AVL_LEFT]->parent = pSwap; - //link our children in - pSwap->child[AVL_LEFT] = pTask->child[AVL_LEFT]; - pSwap->child[AVL_RIGHT] = pTask->child[AVL_RIGHT]; - } - } - } - - //pTask->clear(); - //g_FreeTasks->push(pTask); -} - -static int inserted_tasks = 0; - -void CTaskMngr::insertTask(CTask *pTask, float time, CTask *pRoot) -{ - inserted_tasks++; - int num_ran = 0; - while (true) - { - num_ran++; - float parent = pRoot->nextThink(); - if (time <= parent) - { - if (pRoot->child[AVL_LEFT]) - { - pRoot = pRoot->child[AVL_LEFT]; - continue; - } else { - pTask->balance = 0; - pTask->dir = AVL_LEFT; - pTask->child[AVL_LEFT] = NULL; - pTask->child[AVL_RIGHT] = NULL; - pTask->parent = pRoot; - pRoot->child[AVL_LEFT] = pTask; - //insert us into the linked list. - //we want to be between pRoot and pRoot->prev - pTask->prev = pRoot->prev; //set our previous node - pTask->next = pRoot; //set our next node - if (pRoot->prev) - { - pRoot->prev->next = pTask; //link previous node forward to us - pRoot->prev = pTask; //link next node back to us - } else { - assert(pRoot == first); - pRoot->prev = pTask; - first = pTask; - } - break; - } - } else if (time > parent) { - if (pRoot->child[AVL_RIGHT]) - { - pRoot = pRoot->child[AVL_RIGHT]; - continue; - } else { - pTask->balance = 0; - pTask->dir = AVL_RIGHT; - pTask->child[AVL_LEFT] = NULL; - pTask->child[AVL_RIGHT] = NULL; - pTask->parent = pRoot; - pRoot->child[AVL_RIGHT] = pTask; - //insert us into the linked list. - //we want to be between pRoot and pRoot->next - pTask->next = pRoot->next; //set our next node - pTask->prev = pRoot; //set our previous node - if (pRoot->next) - pRoot->next->prev = pTask; //link next node back to us - pRoot->next = pTask; //link previous node forward to us - break; - } - } - } - //:TODO: rebalance the tree! -} - -void CTaskMngr::insertTask(CTask *pTask) -{ - if (root == NULL) - { - pTask->parent = NULL; - pTask->child[AVL_LEFT] = NULL; - pTask->child[AVL_RIGHT] = NULL; - pTask->next = NULL; - pTask->prev = NULL; - pTask->balance = 0; - pTask->dir = AVL_PARENT; - root = pTask; - first = pTask; - } else { - float num = pTask->nextThink(); - insertTask(pTask, num, root); + if (iter->isFree()) + continue; + iter->executeIfRequired(*m_pTmr_CurrentTime, *m_pTmr_TimeLimit, *m_pTmr_TimeLeft); } } void CTaskMngr::clear() { - if (g_FreeTasks) - { - while (!g_FreeTasks->empty()) - { - delete g_FreeTasks->front(); - g_FreeTasks->pop(); - } - } - - //:TODO: Free the linked list + m_Tasks.clear(); } diff --git a/amxmodx/CTask.h b/amxmodx/CTask.h index f00a67bf..223d42f1 100755 --- a/amxmodx/CTask.h +++ b/amxmodx/CTask.h @@ -32,76 +32,78 @@ #ifndef CTASK_H #define CTASK_H -#define AVL_LEFT 0 -#define AVL_RIGHT 1 -#define AVL_PARENT -1 - -#include "sh_list.h" - class CTaskMngr { -public: - enum - { - Task_Nothing = 0, - Task_Done, - Task_Rel - }; +private: /*** class CTask ***/ class CTask { - friend class CTaskMngr; - //plugin + // task settings + CPluginMngr::CPlugin *m_pPlugin; - //task ID cell m_iId; - //registered forward int m_iFunc; - //number of times to repeat int m_iRepeat; - //type of task (a|b, c, d) - int type; - // for normal tasks, stores the interval, for the others, stores the amount of time before start / after end - float m_fBase; - //Number of parameters - int m_iParamLen; - //Parameter array - cell *m_pParams; - //Size of parameter array - cell m_ParamSize; - //next execution - float m_fNextExecTime; - //will we repeat? + bool m_bLoop; - private: - //Tasks are both a binary tree and a doubly-linked list... - //The path of execution is stored in the linked list. - //The search tree is for fast insertion. - CTask *next; - CTask *prev; - CTask *child[2]; - CTask *parent; - //balance factor for AVL trees - char balance; - int dir; + bool m_bAfterStart; + bool m_bBeforeEnd; + float m_fBase; // for normal tasks, stores the interval, for the others, stores the amount of time before start / after end + int m_iParamLen; + + cell *m_pParams; + bool m_bFree; + + // execution + float m_fNextExecTime; public: void set(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, cell iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat, float fCurrentTime); void clear(); bool isFree() const; + CPluginMngr::CPlugin *getPlugin() const; int getTaskId() const; - int executeIfRequired(float fCurrentTime, float fTimeLimit, float fTimeLeft); + + void executeIfRequired(float fCurrentTime, float fTimeLimit, float fTimeLeft); // also removes the task if needed + void changeBase(float fNewBase); void resetNextExecTime(float fCurrentTime); + bool shouldRepeat(); - float nextThink(); + CTask(); ~CTask(); }; + class CTaskDescriptor + { + public: + cell m_iId; + AMX *m_pAmx; + bool m_bFree; + + CTaskDescriptor(int iId, AMX *pAmx, bool bFree = false) + { + m_iId = iId; + m_pAmx = pAmx; + m_bFree = bFree; + } + + friend bool operator == (const CTask &left, const CTaskDescriptor &right) + { + if (right.m_bFree) + return left.isFree(); + + return !left.isFree() && (right.m_pAmx ? left.getPlugin()->getAMX() == right.m_pAmx : true) && left.getTaskId() == right.m_iId; + } + }; + /*** CTaskMngr priv members ***/ - CTask *root; - CTask *first; + typedef CList TaskList; + typedef TaskList::iterator TaskListIter; + + TaskList m_Tasks; + float *m_pTmr_CurrentTime; float *m_pTmr_TimeLimit; float *m_pTmr_TimeLeft; @@ -109,22 +111,15 @@ public: CTaskMngr(); ~CTaskMngr(); - inline float CurrentTime() { return *m_pTmr_CurrentTime; } - inline float TimeLimit() { return *m_pTmr_TimeLimit; } - inline float TimeLeft() { return *m_pTmr_TimeLeft; } void registerTimers(float *pCurrentTime, float *pTimeLimit, float *pTimeLeft); // The timers will always point to the right value void registerTask(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, cell iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat); - void insertTask(CTask *pTask); - void removeTask(CTask *pTask); int removeTasks(int iId, AMX *pAmx); // remove all tasks that match the id and amx int changeTasks(int iId, AMX *pAmx, float fNewBase); // change all tasks that match the id and amx bool taskExists(int iId, AMX *pAmx); void startFrame(); void clear(); -private: - void insertTask(CTask *pTask, float time, CTask *pRoot); }; #endif //CTASK_H