extern "C" { #include #include #include } #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)(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)(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 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; }