reverted tasks to v1.60

This commit is contained in:
Borja Ferrer 2006-01-06 05:10:17 +00:00
parent 0d3055e505
commit b46ee941d4
2 changed files with 138 additions and 435 deletions

View File

@ -31,9 +31,6 @@
#include "amxmodx.h"
#include "CTask.h"
#include "sh_stack.h"
CStack<CTaskMngr::CTask *> *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::CTask *>();
}
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();
}

View File

@ -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<CTask, CTaskDescriptor> 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