rewritten

This commit is contained in:
Pavol Marko 2004-07-18 18:48:20 +00:00
parent 59bb24e791
commit a6f7742e86
2 changed files with 252 additions and 220 deletions

View File

@ -32,173 +32,214 @@
#include "amxmodx.h" #include "amxmodx.h"
#include "CTask.h" #include "CTask.h"
/*********************** CTask ***********************/
int CTaskMngr::CTask::getTaskId() const
{
return m_iId;
}
CTaskMngr::CTask::CTask( CPluginMngr::CPlugin* p, int f, int flags, CPluginMngr::CPlugin *CTaskMngr::CTask::getPlugin() const
int i, float base, float exec, int parlen , {
const cell* par, int r){ return m_pPlugin;
plugin = p; }
func = f;
id = i;
next = 0;
prev = 0;
param_len = 0;
param = 0;
base_time = base;
exec_time = exec;
repeat = (flags & 1) ? r : 0;
loop = (flags & 2) ? true : false;
afterstart = (flags & 4) ? true : false;
beforeend = (flags & 8) ? true : false;
if ( parlen ) void CTaskMngr::CTask::set(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, int iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat, float fCurrentTime)
{
m_bFree = false;
m_pPlugin = pPlugin;
m_iFunc = iFunc;
m_iId = iId;
m_fBase = fBase;
m_iRepeat = (iFlags & 1) ? iRepeat : 0;
m_bLoop = (iFlags & 2) ? true : false;
m_bAfterStart = (iFlags & 4) ? true : false;
m_bBeforeEnd = (iFlags & 8) ? true : false;
m_fNextExecTime = fCurrentTime + m_fBase;
if (iParamsLen)
{ {
param = new cell[ parlen + 1 ]; // also add a cell to the back with the value 0
m_iParamLen = iParamsLen + 1;
m_pParams = new cell[m_iParamLen];
memcpy(m_pParams, pParams, sizeof(cell)*iParamsLen);
m_pParams[iParamsLen] = 0;
}
else
{
m_iParamLen = 0;
m_pParams = NULL;
}
}
if ( param ){ void CTaskMngr::CTask::clear()
param_len = parlen + 1; {
memcpy( param , par , sizeof( cell ) * parlen ); m_bFree = true;
param[ parlen ] = 0; if (m_pParams)
delete [] m_pParams;
}
bool CTaskMngr::CTask::isFree() const
{
return m_bFree;
}
void CTaskMngr::CTask::changeBase(float fNewBase)
{
m_fBase = fNewBase;
}
void CTaskMngr::CTask::resetNextExecTime(float fCurrentTime)
{
m_fNextExecTime = fCurrentTime + m_fBase;
}
void CTaskMngr::CTask::executeIfRequired(float fCurrentTime, float fTimeLimit, float fTimeLeft)
{
bool execute=false;
if (m_bAfterStart)
{
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)
{
if (m_pPlugin->isExecutable(m_iFunc))
{
int err;
if (m_iParamLen) // call with parameters
{
cell amx_addr, *phys_addr;
if (amx_Allot(m_pPlugin->getAMX(), m_iParamLen, &amx_addr, &phys_addr) != AMX_ERR_NONE)
AMXXLOG_Log("[AMXX] Failed to allocate AMX memory (task \"%d\") (plugin \"%s\")", m_iId, m_pPlugin->getName());
else
{
copy_amxmemory(phys_addr, m_pParams, m_iParamLen);
if ((err = amx_Exec(m_pPlugin->getAMX(), NULL, m_iFunc, 2, amx_addr, m_iId)) != AMX_ERR_NONE)
AMXXLOG_Log("[AMXX] Run time error %d on line %ld (task \"%d\") (plugin \"%s\")", err, m_pPlugin->getAMX()->curline, m_iId, m_pPlugin->getName());
amx_Release(m_pPlugin->getAMX(), amx_addr);
}
}
else
{
if ((err = amx_Exec(m_pPlugin->getAMX(), NULL, m_iFunc, 1, m_iId)) != AMX_ERR_NONE)
AMXXLOG_Log("[AMXX] Run time error %d on line %ld (task \"%d\") (plugin \"%s\")", err, m_pPlugin->getAMX()->curline, m_iId, m_pPlugin->getName());
}
}
// set new exec time OR remove the task if needed
if (m_bLoop || (--m_iRepeat > 0))
{
m_fNextExecTime += m_fBase;
}
else
{
m_bFree = true;
} }
} }
} }
CTaskMngr::CTask* CTaskMngr::getFirstValidTask(CTask* h){ CTaskMngr::CTask::CTask()
CTask* a = h; {
while( a ) { m_bFree = true;
if ( a->isRemoved() ) {
CTask* b = a->next;
unlink( a );
delete a;
a = b;
continue;
}
else if ( a->afterstart ){
if ( *m_timer - *m_timeleft + 1 < a->base_time ) {
a = a->next;
continue;
}
}
else if ( a->beforeend ){
if ( *m_timelimit == 0 ){
a = a->next;
continue;
}
if ( (*m_timeleft + *m_timelimit * 60.0) - *m_timer - 1 >
a->base_time ){
a = a->next;
continue;
}
}
else if ( a->exec_time > *m_timer ) {
a = a->next;
continue;
}
return a;
}
return 0;
} }
CTaskMngr::CTask* CTaskMngr::getNextTask(CTask* a) { CTaskMngr::CTask::~CTask()
if ( a->isRemoved() ) {
return a->next;
if ( a->loop || a->isToReply() ){
a->exec_time = *m_timer + a->base_time;
return a->next;
}
a->setToRemove();
return a->next;
}
CTaskMngr::CTaskMngr() {
head = 0;
tail = 0;
m_timer = 0;
m_timelimit = 0;
m_timeleft = 0;
}
CTaskMngr::~CTaskMngr() {
clear(); clear();
} }
void CTaskMngr::clear() { /*********************** CTaskMngr ***********************/
while ( head ) { CTaskMngr::CTaskMngr()
tail = head->next;
delete head;
head = tail;
}
}
void CTaskMngr::registerTimers( float* timer , float* timelimit, float* timeleft ) {
m_timer = timer;
m_timelimit = timelimit;
m_timeleft = timeleft;
}
void CTaskMngr::registerTask( CPluginMngr::CPlugin* plugin, int func,
int flags, int i, float base, float exec,
int parlen , const cell* par, int repeat ){
CTask* a = new CTask(plugin,func,flags,i,base,exec,parlen,par,repeat );
if ( a == 0 ) return;
if ( tail )
{
tail->next = a;
a->prev = tail;
tail = a;
}
else {
head = a;
tail = a;
}
}
CTaskMngr::CTask* CTaskMngr::findTask( int id , AMX* amx )
{ {
for (CTask* a = head; a ; a = a->next) m_pTmr_CurrentTime = NULL;
{ m_pTmr_TimeLimit = NULL;
if ( !a->isRemoved() && (a->getTaskId() == id) && (!amx || m_pTmr_TimeLeft = NULL;
(a->getPlugin()->getAMX() == amx)) )
return a;
}
return 0;
} }
int CTaskMngr::changeTask(int id, AMX *amx, float flNewTime) void CTaskMngr::registerTimers(float *pCurrentTime, float *pTimeLimit, float *pTimeLeft)
{ {
CTask *a; m_pTmr_CurrentTime = pCurrentTime;
int i = 0; m_pTmr_TimeLimit = pTimeLimit;
m_pTmr_TimeLeft = pTimeLeft;
}
while ( (a=findTask(id, amx)) != 0) void CTaskMngr::registerTask(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, int iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat)
{
// first, search for free tasks
TaskListIter iter = m_Tasks.find(CTaskDescriptor(0, NULL, true));
if (iter)
{ {
a->changeTime(flNewTime > 0.1 ? flNewTime : 0.1); // found: reuse it
iter->set(pPlugin, iFunc, iFlags, iId, fBase, iParamsLen, pParams, iRepeat, *m_pTmr_CurrentTime);
}
else
{
// not found: make a new one
CTask *pTmp = new CTask;
if (!pTmp)
return;
pTmp->set(pPlugin, iFunc, iFlags, iId, fBase, iParamsLen, pParams, iRepeat, *m_pTmr_CurrentTime);
m_Tasks.put(pTmp);
}
}
int CTaskMngr::removeTasks(int iId, AMX *pAmx)
{
CTaskDescriptor descriptor(iId, pAmx);
TaskListIter iter = m_Tasks.find(descriptor);
int i=0;
while (iter)
{
iter->clear();
++i; ++i;
iter = m_Tasks.find(++iter, descriptor);
} }
return i; return i;
} }
void CTaskMngr::unlink(CTask* a){ int CTaskMngr::changeTasks(int iId, AMX *pAmx, float fNewBase)
if ( a->prev ) a->prev->next = a->next;
else head = a->next;
if ( a->next ) a->next->prev = a->prev;
else tail = a->prev;
}
int CTaskMngr::removeTasks( int id , AMX* amx )
{ {
CTask* a; CTaskDescriptor descriptor(iId, pAmx);
int i = 0; TaskListIter iter = m_Tasks.find(descriptor);
int i=0;
while ( (a = findTask(id, amx )) != 0 ) { while (iter)
a->setToRemove(); {
iter->changeBase(fNewBase);
iter->resetNextExecTime(*m_pTmr_CurrentTime);
++i; ++i;
iter = m_Tasks.find(++iter, descriptor);
} }
return i; return i;
} }
bool CTaskMngr::taskExists(int iId, AMX *pAmx)
{
return m_Tasks.find(CTaskDescriptor(iId, pAmx));
}
void CTaskMngr::startFrame()
{
for (TaskListIter iter = m_Tasks.begin(); iter; ++iter)
{
if (iter->isFree())
continue;
iter->executeIfRequired(*m_pTmr_CurrentTime, *m_pTmr_TimeLimit, *m_pTmr_TimeLeft);
}
}
void CTaskMngr::clear()
{
m_Tasks.clear();
}

View File

@ -32,97 +32,88 @@
#ifndef CTASK_H #ifndef CTASK_H
#define CTASK_H #define CTASK_H
// *****************************************************
// class CTaskMngr
// *****************************************************
class CTaskMngr class CTaskMngr
{ {
public: private:
/*** class CTask ***/
class iterator;
class CTask class CTask
{ {
// task settings
CPluginMngr::CPlugin *m_pPlugin;
int m_iId;
int m_iFunc;
int m_iRepeat;
bool m_bLoop;
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;
friend class iterator; // execution
friend class CTaskMngr; float m_fNextExecTime;
CPluginMngr::CPlugin* plugin;
int id;
int func;
int repeat;
bool loop;
bool afterstart;
bool beforeend;
float base_time;
float exec_time;
int param_len;
cell* param;
CTask* next;
CTask* prev;
inline void setToRemove() { exec_time = -1.0f; }
inline void changeTime(float flNewTime) { exec_time = flNewTime; }
inline bool isToReply() { return (repeat-- > 0); }
inline bool isRemoved() { return (exec_time == -1.0f); }
CTask( CPluginMngr::CPlugin* p, int f, int flags, int i,
float base, float exec, int parlen , const cell* par, int r );
~CTask() { if ( param_len ) delete[] param; }
public: public:
inline void set(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, int iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat, float fCurrentTime);
inline void clear();
inline bool isFree() const;
inline int getParamLen() { return param_len; } inline CPluginMngr::CPlugin *getPlugin() const;
inline int getTaskId() { return id; } inline int getTaskId() const;
inline int getFunction() { return func; }
cell* getParam() { return param; } inline void executeIfRequired(float fCurrentTime, float fTimeLimit, float fTimeLeft); // also removes the task if needed
CPluginMngr::CPlugin* getPlugin() { return plugin; }
inline void changeBase(float fNewBase);
inline void resetNextExecTime(float fCurrentTime);
inline bool shouldRepeat();
CTask();
~CTask();
}; };
class CTaskDescriptor
{
private:
friend class iterator;
CTask *head;
CTask *tail;
float* m_timer;
float* m_timelimit;
float* m_timeleft;
CTask* getFirstValidTask(CTask* a);
CTask* getNextTask(CTask* a);
CTask* findTask( int id , AMX* amx );
void unlink(CTask* a);
public:
CTaskMngr();
~CTaskMngr();
// Interface
void registerTimers( float* timer , float* timelimit, float* timeleft );
void registerTask( CPluginMngr::CPlugin* plugin, int func, int flags, int i, float base, float exec, int parlen , const cell* par, int repeat );
inline int taskExists( int id ,AMX* amx) { return findTask(id,amx ) ? 1 : 0; }
int changeTask(int id, AMX *amx, float flNewTime);
int removeTasks( int id , AMX* amx );
void clear();
class iterator {
CTask* a;
CTaskMngr* b;
public: public:
iterator(CTask*aa,CTaskMngr* bb) : a(aa), b(bb) {} int m_iId;
iterator& operator++() { AMX *m_pAmx;
a = b->getNextTask( a ); bool m_bFree;
a = b->getFirstValidTask( a );
return *this; CTaskDescriptor(int iId, AMX *pAmx, bool bFree = false)
{
m_iId = iId;
m_pAmx = pAmx;
m_bFree = bFree;
} }
CTask& operator*() { return *a; }
operator bool ( ) const { return a ? true : false; }
};
inline iterator begin() { return iterator(getFirstValidTask(head),this); }
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 ***/
typedef CList<CTask, CTaskDescriptor> TaskList;
typedef TaskList::iterator TaskListIter;
TaskList m_Tasks;
float *m_pTmr_CurrentTime;
float *m_pTmr_TimeLimit;
float *m_pTmr_TimeLeft;
public:
CTaskMngr();
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, int iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat);
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();
}; };
#endif #endif