NS/main/source/scriptengine/AvHLUATime.cpp

164 lines
3.9 KiB
C++

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#include "scriptengine/AvHLUA.h"
#include "scriptengine/AvHLUAUtil.h"
#ifdef AVH_CLIENT
extern double gClientTimeLastUpdate;
#endif
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static int AvHLUATime_Now(lua_State *L)
{
#ifdef AVH_SERVER
float now = gpGlobals->time;
#else
float now = gClientTimeLastUpdate;
#endif
lua_pushnumber(L, (float)(now));
return 1;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static int AvHLUATime_Sleep(lua_State *L)
{
float sleeptime = (float)(luaL_checknumber(L, 1));
if (sleeptime > 0)
{
return gLUA->Suspend(L, sleeptime);
}
else
{
return gLUA->Suspend(L, 0);
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static int AvHLUATime_At(lua_State *L)
{
float time = (float)(luaL_checknumber(L, 1));
luaL_checktype(L, 2, LUA_TSTRING);
gLUA->DelayedExecute(L, time);
return 0;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static const luaL_reg meta_methods [] = {
{0,0}
};
static const luaL_reg time_methods [] = {
{"Now", AvHLUATime_Now},
{"Sleep", AvHLUATime_Sleep},
{"At", AvHLUATime_At},
{0,0}
};
void AvHLUA::RegisterNamespace_Time()
{
UTIL_LUARegisterObject(this->mGlobalContext, time_methods, meta_methods, "Time");
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int AvHLUA::DelayedExecute(lua_State *L, float time)
{
int args = lua_gettop(L) - 2;
lua_State *threadContext = lua_newthread(L);
lua_getglobal(threadContext, lua_tostring(L, 2));
if (args > 0)
{
lua_xmove(L, threadContext, args + 1);
lua_pop(threadContext, 1);
}
this->mTimetable.insert(pair<float, LUATimetableCallbackType>((float)(time), LUATimetableCallbackType(args, threadContext)));
LUATimetableType::iterator firstCall = this->mTimetable.begin();
this->mNextCallTime = (float)((*firstCall).first);
return 0;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int AvHLUA::Suspend(lua_State *L, float delay)
{
#ifdef AVH_SERVER
float now = gpGlobals->time;
#else
float now = gClientTimeLastUpdate;
#endif
this->mTimetable.insert(pair<float, LUATimetableCallbackType>((float)(now + delay), LUATimetableCallbackType(0, L)));
LUATimetableType::iterator firstCall = this->mTimetable.begin();
this->mNextCallTime = (float)((*firstCall).first);
return (lua_yield(L, 0));
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int AvHLUA::Resume(lua_State *L, int numargs)
{
int errorcode = lua_resume(L, numargs);
if (errorcode)
{
AvHLUA_OnError(lua_tostring(L, -1));
}
return errorcode;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool AvHLUA::ExecuteCallbacks(float time)
{
if (time < this->mNextCallTime)
return false;
LUATimetableType::iterator TimetableStart = this->mTimetable.begin();
LUATimetableType::iterator TimetableEnd = this->mTimetable.end();
list<LUATimetableType::iterator> eraseList;
LUATimetableType::iterator current = TimetableStart;
while (current != TimetableEnd)
{
float calltime = (float)((*current).first);
if (calltime < time)
{
LUATimetableCallbackType callbackfunc = (*current).second;
int numargs = callbackfunc.first;
lua_State *L = callbackfunc.second;
this->Resume(L, numargs);
eraseList.push_back(current);
current++;
}
else
{
this->mNextCallTime = calltime;
break;
}
}
if (current == TimetableEnd)
{
#ifdef AVH_SERVER
this->mNextCallTime = gpGlobals->time + 99999;
#else
this->mNextCallTime = gClientTimeLastUpdate + 99999;
#endif
}
while (eraseList.size() > 0)
{
LUATimetableType::iterator toErase = eraseList.front();
this->mTimetable.erase(toErase);
eraseList.pop_front();
}
return true;
}