//////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . //////////////////////////////////////////////////////////////////////// #include "otpch.h" #include #include #include "globalevent.h" #include "tools.h" #include "player.h" GlobalEvents::GlobalEvents(): m_scriptInterface("GlobalEvent Interface") { m_scriptInterface.initState(); } GlobalEvents::~GlobalEvents() { clear(); } void GlobalEvents::clearMap(GlobalEventMap& map) { GlobalEventMap::iterator it; for(it = map.begin(); it != map.end(); ++it) delete it->second; map.clear(); } void GlobalEvents::clear() { clearMap(thinkMap); clearMap(serverMap); clearMap(timerMap); m_scriptInterface.reInitState(); } Event* GlobalEvents::getEvent(const std::string& nodeName) { if(asLowerCaseString(nodeName) == "globalevent") return new GlobalEvent(&m_scriptInterface); return NULL; } bool GlobalEvents::registerEvent(Event* event, xmlNodePtr p, bool override) { GlobalEvent* globalEvent = dynamic_cast(event); if(!globalEvent) return false; GlobalEventMap* map = &thinkMap; if(globalEvent->getEventType() == GLOBAL_EVENT_TIMER) map = &timerMap; else if(globalEvent->getEventType() != GLOBAL_EVENT_NONE) map = &serverMap; GlobalEventMap::iterator it = map->find(globalEvent->getName()); if(it == map->end()) { map->insert(std::make_pair(globalEvent->getName(), globalEvent)); return true; } if(override) { delete it->second; it->second = globalEvent; return true; } std::cout << "[Warning - GlobalEvents::configureEvent] Duplicate registered globalevent with name: " << globalEvent->getName() << std::endl; return false; } void GlobalEvents::startup() { time_t now = time(NULL); tm* ts = localtime(&now); now = std::max(1, (int32_t)(60 - ts->tm_sec)) * 1000; execute(GLOBAL_EVENT_STARTUP); Scheduler::getScheduler().addEvent(createSchedulerTask((int32_t)now, boost::bind(&GlobalEvents::timer, this))); Scheduler::getScheduler().addEvent(createSchedulerTask(GLOBAL_THINK_INTERVAL, boost::bind(&GlobalEvents::think, this, GLOBAL_THINK_INTERVAL))); } void GlobalEvents::timer() { time_t now = time(NULL); tm* ts = localtime(&now); uint32_t hour = (uint32_t)ts->tm_hour, minute = (uint32_t)ts->tm_min; for(GlobalEventMap::iterator it = timerMap.begin(); it != timerMap.end(); ++it) { if(hour != it->second->getHour() || minute != it->second->getMinute()) continue; if(!it->second->executeEvent()) std::cout << "[Error - GlobalEvents::timer] Couldn't execute event: " << it->second->getName() << std::endl; } now = std::max(1, (int32_t)(60 - ts->tm_sec)) * 1000; Scheduler::getScheduler().addEvent(createSchedulerTask((int32_t)now, boost::bind(&GlobalEvents::timer, this))); } void GlobalEvents::think(uint32_t interval) { time_t now = time(NULL); for(GlobalEventMap::iterator it = thinkMap.begin(); it != thinkMap.end(); ++it) { if(now <= (it->second->getLastExecution() + it->second->getInterval())) continue; it->second->setLastExecution(now); if(!it->second->executeThink(it->second->getInterval(), now, interval)) std::cout << "[Error - GlobalEvents::think] Couldn't execute event: " << it->second->getName() << std::endl; } Scheduler::getScheduler().addEvent(createSchedulerTask(interval, boost::bind(&GlobalEvents::think, this, interval))); } void GlobalEvents::execute(GlobalEvent_t type) { for(GlobalEventMap::iterator it = serverMap.begin(); it != serverMap.end(); ++it) { if(it->second->getEventType() == type) it->second->executeEvent(); } } GlobalEventMap GlobalEvents::getEventMap(GlobalEvent_t type) { switch(type) { case GLOBAL_EVENT_NONE: return thinkMap; case GLOBAL_EVENT_TIMER: return timerMap; case GLOBAL_EVENT_STARTUP: case GLOBAL_EVENT_SHUTDOWN: case GLOBAL_EVENT_RECORD: { GlobalEventMap retMap; for(GlobalEventMap::iterator it = serverMap.begin(); it != serverMap.end(); ++it) { if(it->second->getEventType() == type) retMap[it->first] = it->second; } return retMap; } default: break; } return GlobalEventMap(); } GlobalEvent::GlobalEvent(LuaScriptInterface* _interface): Event(_interface) { m_lastExecution = time(NULL); m_hour = m_minute = 0; } bool GlobalEvent::configureEvent(xmlNodePtr p) { std::string strValue; if(!readXMLString(p, "name", strValue)) { std::cout << "[Error - GlobalEvent::configureEvent] No name for a globalevent." << std::endl; return false; } m_name = strValue; m_eventType = GLOBAL_EVENT_NONE; if(readXMLString(p, "type", strValue)) { std::string tmpStrValue = asLowerCaseString(strValue); if(tmpStrValue == "startup" || tmpStrValue == "start" || tmpStrValue == "load") m_eventType = GLOBAL_EVENT_STARTUP; else if(tmpStrValue == "shutdown" || tmpStrValue == "quit" || tmpStrValue == "exit") m_eventType = GLOBAL_EVENT_SHUTDOWN; else if(tmpStrValue == "record" || tmpStrValue == "playersrecord") m_eventType = GLOBAL_EVENT_RECORD; else { std::cout << "[Error - GlobalEvent::configureEvent] No valid type \"" << strValue << "\" for globalevent with name " << m_name << std::endl; return false; } return true; } else if(readXMLString(p, "time", strValue) || readXMLString(p, "at", strValue)) { IntegerVec params = vectorAtoi(explodeString(strValue, ":")); if(params.size() < 2 || params[0] > 23 || params[0] < 0 || params[1] > 59 || params[1] < 0) { std::cout << "[Error - GlobalEvent::configureEvent] No valid time \"" << strValue << "\" for globalevent with name " << m_name << std::endl; return false; } m_hour = params[0], m_minute = params[1]; m_eventType = GLOBAL_EVENT_TIMER; return true; } else { int32_t intValue; if(readXMLInteger(p, "interval", intValue)) { m_interval = intValue; return true; } } std::cout << "[Error - GlobalEvent::configureEvent] No interval for globalevent with name " << m_name << std::endl; return false; } std::string GlobalEvent::getScriptEventName() const { switch(m_eventType) { case GLOBAL_EVENT_STARTUP: return "onStartup"; case GLOBAL_EVENT_SHUTDOWN: return "onShutdown"; case GLOBAL_EVENT_RECORD: return "onRecord"; case GLOBAL_EVENT_TIMER: return "onTimer"; default: return "onThink"; } } std::string GlobalEvent::getScriptEventParams() const { switch(m_eventType) { case GLOBAL_EVENT_RECORD: return "current, old, cid"; case GLOBAL_EVENT_NONE: return "interval, lastExecution, thinkInterval"; default: return ""; } } int32_t GlobalEvent::executeThink(uint32_t interval, uint32_t lastExecution, uint32_t thinkInterval) { //onThink(interval, lastExecution, thinkInterval) if(m_scriptInterface->reserveScriptEnv()) { ScriptEnviroment* env = m_scriptInterface->getScriptEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { std::stringstream scriptstream; scriptstream << "local interval = " << interval << std::endl; scriptstream << "local lastExecution = " << lastExecution << std::endl; scriptstream << "local thinkInterval = " << thinkInterval << std::endl; scriptstream << m_scriptData; bool result = true; if(m_scriptInterface->loadBuffer(scriptstream.str()) != -1) { lua_State* L = m_scriptInterface->getLuaState(); result = m_scriptInterface->getGlobalBool(L, "_result", true); } m_scriptInterface->releaseScriptEnv(); return result; } else { #ifdef __DEBUG_LUASCRIPTS__ char desc[125]; sprintf(desc, "%s - %i (%i)", getName().c_str(), interval, lastExecution); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_scriptInterface); lua_State* L = m_scriptInterface->getLuaState(); m_scriptInterface->pushFunction(m_scriptId); lua_pushnumber(L, interval); lua_pushnumber(L, lastExecution); lua_pushnumber(L, thinkInterval); bool result = m_scriptInterface->callFunction(3); m_scriptInterface->releaseScriptEnv(); return result; } } else { std::cout << "[Error - GlobalEvent::executeThink] Call stack overflow." << std::endl; return 0; } } int32_t GlobalEvent::executeRecord(uint32_t current, uint32_t old, Player* player) { //onRecord(current, old, cid) if(m_scriptInterface->reserveScriptEnv()) { ScriptEnviroment* env = m_scriptInterface->getScriptEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { std::stringstream scriptstream; scriptstream << "local current = " << current << std::endl; scriptstream << "local old = " << old << std::endl; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << m_scriptData; bool result = true; if(m_scriptInterface->loadBuffer(scriptstream.str()) != -1) { lua_State* L = m_scriptInterface->getLuaState(); result = m_scriptInterface->getGlobalBool(L, "_result", true); } m_scriptInterface->releaseScriptEnv(); return result; } else { #ifdef __DEBUG_LUASCRIPTS__ char desc[125]; sprintf(desc, "%s - %i to %i (%i)", getName().c_str(), old, current, player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_scriptInterface); lua_State* L = m_scriptInterface->getLuaState(); m_scriptInterface->pushFunction(m_scriptId); lua_pushnumber(L, current); lua_pushnumber(L, old); lua_pushnumber(L, env->addThing(player)); bool result = m_scriptInterface->callFunction(3); m_scriptInterface->releaseScriptEnv(); return result; } } else { std::cout << "[Error - GlobalEvent::executeRecord] Call stack overflow." << std::endl; return 0; } } int32_t GlobalEvent::executeEvent() { if(m_scriptInterface->reserveScriptEnv()) { ScriptEnviroment* env = m_scriptInterface->getScriptEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { bool result = true; if(m_scriptInterface->loadBuffer(m_scriptData) != -1) { lua_State* L = m_scriptInterface->getLuaState(); result = m_scriptInterface->getGlobalBool(L, "_result", true); } m_scriptInterface->releaseScriptEnv(); return result; } else { env->setScriptId(m_scriptId, m_scriptInterface); m_scriptInterface->pushFunction(m_scriptId); bool result = m_scriptInterface->callFunction(0); m_scriptInterface->releaseScriptEnv(); return result; } } else { std::cout << "[Error - GlobalEvent::executeEvent] Call stack overflow." << std::endl; return 0; } }