/*
* Copyright (C) 2010 - 2014 Eluna Lua Engine
* This program is free software licensed under GPL version 3
* Please see the included DOCS/LICENSE.md for more information
*/
#include
#include
#include "LuaEngine.h"
#ifdef MANGOS
INSTANTIATE_SINGLETON_1(Eluna);
#endif
extern void RegisterFunctions(lua_State* L);
extern void AddElunaScripts();
// Start or restart eluna. Returns true if started
bool StartEluna()
{
#ifndef ELUNA
#ifndef MANGOS
{
ELUNA_LOG_ERROR("[Eluna]: LuaEngine is Disabled. (If you want to use it please enable in cmake)");
return false;
}
#endif
#endif
ELUNA_GUARD();
bool restart = false;
if (sEluna->L)
{
restart = true;
sHookMgr->OnEngineRestart();
ELUNA_LOG_INFO("[Eluna]: Stopping Lua Engine");
// Unregisters and stops all timed events
sEluna->m_EventMgr.RemoveEvents();
// Remove bindings
sEluna->PacketEventBindings.Clear();
sEluna->ServerEventBindings.Clear();
sEluna->PlayerEventBindings.Clear();
sEluna->GuildEventBindings.Clear();
sEluna->GroupEventBindings.Clear();
sEluna->CreatureEventBindings.Clear();
sEluna->CreatureGossipBindings.Clear();
sEluna->GameObjectEventBindings.Clear();
sEluna->GameObjectGossipBindings.Clear();
sEluna->ItemEventBindings.Clear();
sEluna->ItemGossipBindings.Clear();
sEluna->playerGossipBindings.Clear();
sEluna->VehicleEventBindings.Clear();
lua_close(sEluna->L);
}
else
AddElunaScripts();
#ifdef MANGOS
// Check config file for eluna is enabled or disabled
if (!sWorld->getConfig(CONFIG_BOOL_ELUNA_ENABLED))
{
ELUNA_LOG_ERROR("[Eluna]: LuaEngine is Disabled. (If you want to use it please set config in 'mangosd.conf')");
return false;
}
#endif
ELUNA_LOG_INFO("[Eluna]: Starting Lua Engine");
sEluna->L = luaL_newstate();
luaL_openlibs(sEluna->L);
RegisterFunctions(sEluna->L);
ScriptPaths scripts;
std::string folderpath = sConfigMgr->GetStringDefault("Eluna.ScriptPath", "lua_scripts");
#if PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE
if (folderpath[0] == '~')
if (const char* home = getenv("HOME");)
folderpath.replace(0, 1, home);
#endif
ELUNA_LOG_INFO("[Eluna]: Searching scripts from `%s`", folderpath.c_str());
sEluna->GetScripts(folderpath, scripts);
sEluna->GetScripts(folderpath+"/extensions", scripts);
sEluna->RunScripts(scripts);
/*
if (restart)
{
//! Iterate over every supported source type (creature and gameobject)
//! Not entirely sure how this will affect units in non-loaded grids.
{
HashMapHolder::ReadGuard g(HashMapHolder::GetLock());
HashMapHolder::MapType& m = HashMapHolder::GetContainer();
for (HashMapHolder::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)
{
if (itr->second->IsInWorld()) // must check?
// if(sEluna->CreatureEventBindings->GetBindMap(iter->second->GetEntry())) // update all AI or just Eluna?
itr->second->AIM_Initialize();
}
}
{
HashMapHolder::ReadGuard g(HashMapHolder::GetLock());
HashMapHolder::MapType& m = HashMapHolder::GetContainer();
for (HashMapHolder::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)
{
if (itr->second->IsInWorld()) // must check?
// if(sEluna->GameObjectEventBindings->GetBindMap(iter->second->GetEntry())) // update all AI or just Eluna?
itr->second->AIM_Initialize();
}
}
}
*/
return true;
}
// Finds lua script files from given path (including subdirectories) and pushes them to scripts
void Eluna::GetScripts(std::string path, ScriptPaths& scripts)
{
ELUNA_LOG_DEBUG("[Eluna]: GetScripts from path `%s`", path.c_str());
ACE_Dirent dir;
if (dir.open(path.c_str()) == -1)
{
ELUNA_LOG_ERROR("[Eluna]: Error No `%s` directory found, creating it", path.c_str());
ACE_OS::mkdir(path.c_str());
return;
}
ACE_DIRENT *directory = 0;
while (directory = dir.read())
{
// Skip the ".." and "." files.
if (ACE::isdotdir(directory->d_name))
continue;
std::string fullpath = path + "/" + directory->d_name;
ACE_stat stat_buf;
if (ACE_OS::lstat(fullpath.c_str(), &stat_buf) == -1)
continue;
// load subfolder
if ((stat_buf.st_mode & S_IFMT) == (S_IFDIR))
{
GetScripts(fullpath, scripts);
continue;
}
// was file, check extension
ELUNA_LOG_DEBUG("[Eluna]: GetScripts Checking file `%s`", fullpath.c_str());
std::string ext = fullpath.substr(fullpath.length() - 4, 4);
if (ext != ".lua" && ext != ".dll")
continue;
// was correct, add path to scripts to load
ELUNA_LOG_DEBUG("[Eluna]: GetScripts add path `%s`", fullpath.c_str());
scripts.erase(fullpath);
scripts.insert(fullpath);
}
}
void Eluna::RunScripts(ScriptPaths& scripts)
{
uint32 count = 0;
// load last first to load extensions first
for (ScriptPaths::const_reverse_iterator it = scripts.rbegin(); it != scripts.rend(); ++it)
{
if (!luaL_loadfile(L, it->c_str()) && !lua_pcall(L, 0, 0, 0))
{
// successfully loaded and ran file
ELUNA_LOG_DEBUG("[Eluna]: Successfully loaded `%s`", it->c_str());
++count;
continue;
}
ELUNA_LOG_ERROR("[Eluna]: Error loading file `%s`", it->c_str());
report(L);
}
ELUNA_LOG_INFO("[Eluna]: Loaded %u Lua scripts", count);
}
void Eluna::report(lua_State* L)
{
const char* msg = lua_tostring(L, -1);
while (msg)
{
lua_pop(L, -1);
ELUNA_LOG_ERROR("%s", msg);
msg = lua_tostring(L, -1);
}
}
void Eluna::BeginCall(int fReference)
{
lua_settop(L, 0); // stack should be empty
lua_rawgeti(L, LUA_REGISTRYINDEX, (fReference));
}
bool Eluna::ExecuteCall(int params, int res)
{
bool ret = true;
int top = lua_gettop(L);
if (lua_type(L, top - params) == LUA_TFUNCTION) // is function
{
if (lua_pcall(L, params, res, 0))
{
report(L);
ret = false;
}
}
else
{
ret = false;
if (params > 0)
{
for (int i = top; i >= (top - params); i--)
{
if (!lua_isnone(L, i))
lua_remove(L, i);
}
}
}
return ret;
}
void Eluna::EndCall(int res)
{
for (int i = res; i > 0; i--)
{
if (!lua_isnone(L, res))
lua_remove(L, res);
}
}
void Eluna::Push(lua_State* L)
{
lua_pushnil(L);
}
void Eluna::Push(lua_State* L, const uint64 l)
{
std::ostringstream ss;
ss << l;
sEluna->Push(L, ss.str());
}
void Eluna::Push(lua_State* L, const int64 l)
{
std::ostringstream ss;
ss << l;
sEluna->Push(L, ss.str());
}
void Eluna::Push(lua_State* L, const uint32 u)
{
lua_pushunsigned(L, u);
}
void Eluna::Push(lua_State* L, const int32 i)
{
lua_pushinteger(L, i);
}
void Eluna::Push(lua_State* L, const double d)
{
lua_pushnumber(L, d);
}
void Eluna::Push(lua_State* L, const float f)
{
lua_pushnumber(L, f);
}
void Eluna::Push(lua_State* L, const bool b)
{
lua_pushboolean(L, b);
}
void Eluna::Push(lua_State* L, const std::string str)
{
lua_pushstring(L, str.c_str());
}
void Eluna::Push(lua_State* L, const char* str)
{
lua_pushstring(L, str);
}
void Eluna::Push(lua_State* L, Pet const* pet)
{
Push(L, pet->ToCreature());
}
void Eluna::Push(lua_State* L, TempSummon const* summon)
{
Push(L, summon->ToCreature());
}
void Eluna::Push(lua_State* L, Unit const* unit)
{
if (!unit)
{
Push(L);
return;
}
switch (unit->GetTypeId())
{
case TYPEID_UNIT:
Push(L, unit->ToCreature());
break;
case TYPEID_PLAYER:
Push(L, unit->ToPlayer());
break;
default:
ElunaTemplate::push(L, unit);
}
}
void Eluna::Push(lua_State* L, WorldObject const* obj)
{
if (!obj)
{
Push(L);
return;
}
switch (obj->GetTypeId())
{
case TYPEID_UNIT:
Push(L, obj->ToCreature());
break;
case TYPEID_PLAYER:
Push(L, obj->ToPlayer());
break;
case TYPEID_GAMEOBJECT:
Push(L, obj->ToGameObject());
break;
case TYPEID_CORPSE:
Push(L, obj->ToCorpse());
break;
default:
ElunaTemplate::push(L, obj);
}
}
void Eluna::Push(lua_State* L, Object const* obj)
{
if (!obj)
{
Push(L);
return;
}
switch (obj->GetTypeId())
{
case TYPEID_UNIT:
Push(L, obj->ToCreature());
break;
case TYPEID_PLAYER:
Push(L, obj->ToPlayer());
break;
case TYPEID_GAMEOBJECT:
Push(L, obj->ToGameObject());
break;
case TYPEID_CORPSE:
Push(L, obj->ToCorpse());
break;
default:
ElunaTemplate