/*
* 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 "LuaEngine.h"
#ifdef MANGOS
INSTANTIATE_SINGLETON_1(Eluna);
#endif
#if PLATFORM == PLATFORM_UNIX
#include
#endif
extern void RegisterFunctions(lua_State* L);
extern void AddElunaScripts();
// Start or restart eluna. Returns true if started
bool StartEluna()
{
#ifndef ELUNA
#ifndef MANGOS
{
TC_LOG_ERROR("eluna", "[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();
TC_LOG_INFO("eluna", "[Eluna]: Restarting 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))
{
TC_LOG_ERROR("eluna", "[Eluna]: LuaEngine is Disabled. (If you want to use it please set config in 'mangosd.conf')");
return false;
}
#endif
sEluna->L = luaL_newstate();
TC_LOG_INFO("eluna", "[Eluna]: Lua Engine loaded.");
LoadedScripts loadedScripts;
sEluna->LoadDirectory("lua_scripts", &loadedScripts);
luaL_openlibs(sEluna->L);
RegisterFunctions(sEluna->L);
// Randomize math.random()
// The macro fails on TC for unknown reason
// luaL_dostring(sEluna->L, "math.randomseed( tonumber(tostring(os.time()):reverse():sub(1,6)) )");
if (!luaL_loadstring(sEluna->L, "math.randomseed( tonumber(tostring(os.time()):reverse():sub(1,6)) )"))
lua_pcall(sEluna->L, 0, LUA_MULTRET, 0);
uint32 count = 0;
char filename[200];
for (std::set::const_iterator itr = loadedScripts.begin(); itr != loadedScripts.end(); ++itr)
{
strcpy(filename, itr->c_str());
if (luaL_loadfile(sEluna->L, filename) != 0)
{
TC_LOG_ERROR("eluna", "[Eluna]: Error loading file `%s`.", itr->c_str());
sEluna->report(sEluna->L);
}
else
{
int err = lua_pcall(sEluna->L, 0, 0, 0);
if (err != 0 && err == LUA_ERRRUN)
{
TC_LOG_ERROR("eluna", "[Eluna]: Error loading file `%s`.", itr->c_str());
sEluna->report(sEluna->L);
}
}
++count;
}
/*
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();
}
}
}
*/
TC_LOG_INFO("eluna", "[Eluna]: Loaded %u Lua scripts..", count);
return true;
}
// Loads lua scripts from given directory
void Eluna::LoadDirectory(char* Dirname, LoadedScripts* lscr)
{
#ifdef WIN32
HANDLE hFile;
WIN32_FIND_DATA FindData;
memset(&FindData, 0, sizeof(FindData));
char SearchName[MAX_PATH];
strcpy(SearchName, Dirname);
strcat(SearchName, "\\*.*");
hFile = FindFirstFile(SearchName, &FindData);
if (hFile == INVALID_HANDLE_VALUE)
{
TC_LOG_ERROR("eluna", "[Eluna]: Error No `lua_scripts` directory found! Creating a 'lua_scripts' directory.");
CreateDirectory("lua_scripts", NULL);
return;
}
FindNextFile(hFile, &FindData);
while (FindNextFile(hFile, &FindData))
{
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
strcpy(SearchName, Dirname);
strcat(SearchName, "\\");
strcat(SearchName, FindData.cFileName);
LoadDirectory(SearchName, lscr);
}
else
{
std::string fname = Dirname;
fname += "\\";
fname += FindData.cFileName;
size_t len = strlen(fname.c_str());
int i = 0;
char ext[MAX_PATH];
while (len > 0)
{
ext[i++] = fname[--len];
if (fname[len] == '.')
break;
}
ext[i++] = '\0';
if (!_stricmp(ext, "aul."))
{
TC_LOG_DEBUG("eluna", "[Eluna]: Load File: %s", fname.c_str());
lscr->insert(fname);
}
}
}
FindClose(hFile);
#else
char* dir = strrchr(Dirname, '/');
if (strcmp(Dirname, "..") == 0 || strcmp(Dirname, ".") == 0)
return;
if (dir && (strcmp(dir, "/..") == 0 || strcmp(dir, "/.") == 0 || strcmp(dir, "/.svn") == 0))
return;
struct dirent** list;
int fileCount = scandir(Dirname, &list, 0, 0);
if (fileCount <= 0 || !list)
return;
struct stat attributes;
bool error;
while (fileCount--)
{
char _path[200];
sprintf(_path, "%s/%s", Dirname, list[fileCount]->d_name);
if (stat(_path, &attributes) == -1)
{
error = true;
TC_LOG_ERROR("eluna", "[Eluna]: Error opening `%s`", _path);
}
else
error = false;
if (!error && S_ISDIR(attributes.st_mode))
LoadDirectory((char*)_path, lscr);
else
{
char* ext = strrchr(list[fileCount]->d_name, '.');
if (ext && !strcmp(ext, ".lua"))
lscr->insert(_path);
}
free(list[fileCount]);
}
free(list);
#endif
}
void Eluna::report(lua_State* L)
{
const char* msg = lua_tostring(L, -1);
while (msg)
{
lua_pop(L, -1);
TC_LOG_ERROR("eluna", "%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