Пример #1
0
bool Eluna::ExecuteCall(int params, int res)
{
    int top = lua_gettop(L);
    int base = top - params;

    // Expected: function, [parameters]
    ASSERT(base > 0);

    // Check function type
    if (!lua_isfunction(L, base))
    {
        ELUNA_LOG_ERROR("[Eluna]: Cannot execute call: registered value is %s, not a function.", luaL_tolstring(L, base, NULL));
        ASSERT(false); // stack probably corrupt
    }

    bool usetrace = eConfigMgr->GetBoolDefault("Eluna.TraceBack", false);
    if (usetrace)
    {
        lua_pushcfunction(L, &StackTrace);
        // Stack: function, [parameters], traceback
        lua_insert(L, base);
        // Stack: traceback, function, [parameters]
    }

    // Objects are invalidated when event_level hits 0
    ++event_level;
    int result = lua_pcall(L, params, res, usetrace ? base : 0);
    --event_level;

    if (usetrace)
    {
        // Stack: traceback, [results or errmsg]
        lua_remove(L, base);
    }
    // Stack: [results or errmsg]

    // lua_pcall returns 0 on success.
    // On error print the error and push nils for expected amount of returned values
    if (result)
    {
        // Stack: errmsg
        Report(L);

        // Force garbage collect
        lua_gc(L, LUA_GCCOLLECT, 0);

        // Push nils for expected amount of results
        for (int i = 0; i < res; ++i)
            lua_pushnil(L);
        // Stack: [nils]
        return false;
    }

    // Stack: [results]
    return true;
}
Пример #2
0
// Finds lua script files from given path (including subdirectories) and pushes them to scripts
void Eluna::GetScripts(std::string path, ScriptList& 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());

        // split file name
        std::string filename = directory->d_name;
        uint32 extDot = filename.find_last_of('.');
        if (extDot == std::string::npos)
            continue;
        std::string ext = filename.substr(extDot);
        filename = filename.substr(0, extDot);

        // check extension and add path to scripts to load
        if (ext != ".lua" && ext != ".dll")
            continue;

        LuaScript script;
        script.fileext = ext;
        script.filename = filename;
        script.filepath = fullpath;
        script.modulepath = fullpath.substr(0, fullpath.length() - ext.length());
        scripts.push_back(script);
        ELUNA_LOG_DEBUG("[Eluna]: GetScripts add path `%s`", fullpath.c_str());
    }
}
Пример #3
0
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);
    }
}
Пример #4
0
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);
}
Пример #5
0
// 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);
    }
}
Пример #6
0
void Eluna::RunScripts()
{
    uint32 oldMSTime = GetCurrTime();
    uint32 count = 0;

    ScriptList scripts;
    scripts.insert(scripts.end(), lua_extensions.begin(), lua_extensions.end());
    scripts.insert(scripts.end(), lua_scripts.begin(), lua_scripts.end());

    lua_getglobal(L, "package");
    luaL_getsubtable(L, -1, "loaded");
    int modules = lua_gettop(L);
    for (ScriptList::const_iterator it = scripts.begin(); it != scripts.end(); ++it)
    {
        lua_getfield(L, modules, it->modulepath.c_str());
        if (!lua_isnoneornil(L, -1))
        {
            lua_pop(L, 1);
            ELUNA_LOG_DEBUG("[Eluna]: Extension was already loaded or required `%s`", it->filepath.c_str());
            continue;
        }
        lua_pop(L, 1);
        if (!luaL_loadfile(L, it->filepath.c_str()) && !lua_pcall(L, 0, 1, 0))
        {
            if (!lua_toboolean(L, -1))
            {
                lua_pop(L, 1);
                Push(L, true);
            }
            lua_setfield(L, modules, it->modulepath.c_str());

            // successfully loaded and ran file
            ELUNA_LOG_DEBUG("[Eluna]: Successfully loaded `%s`", it->filepath.c_str());
            ++count;
            continue;
        }
        ELUNA_LOG_ERROR("[Eluna]: Error loading extension `%s`", it->filepath.c_str());
        report(L);
    }
    lua_pop(L, 2);

    ELUNA_LOG_INFO("[Eluna]: Executed %u Lua scripts in %u ms", count, GetTimeDiff(oldMSTime));
}
Пример #7
0
const char* ElunaInstanceAI::Save() const
{
    lua_State* L = instance->GetEluna()->L;
    // Stack: (empty)

    /*
     * Need to cheat because this method actually does modify this instance,
     *   even though it's declared as `const`.
     *
     * Declaring virtual methods as `const` is BAD!
     * Don't dictate to children that their methods must be pure.
     */
    ElunaInstanceAI* self = const_cast<ElunaInstanceAI*>(this);

    lua_pushcfunction(L, mar_encode);
    instance->GetEluna()->PushInstanceData(L, self, false);
    // Stack: mar_encode, instance_data

    if (lua_pcall(L, 1, 1, 0) != 0)
    {
        // Stack: error_message
        ELUNA_LOG_ERROR("Error while saving: %s", lua_tostring(L, -1));
        lua_pop(L, 1);
        return NULL;
    }

    // Stack: data
    size_t dataLength;
    const unsigned char* data = (const unsigned char*)lua_tolstring(L, -1, &dataLength);
    ElunaUtil::EncodeData(data, dataLength, self->lastSaveData);

    lua_pop(L, 1);
    // Stack: (empty)

    return lastSaveData.c_str();
}
Пример #8
0
void ElunaInstanceAI::Load(const char* data)
{
    // If we get passed NULL (i.e. `Reload` was called) then use
    //   the last known save data (or maybe just an empty string).
    if (!data)
    {
        data = lastSaveData.c_str();
    }
    else // Otherwise, copy the new data into our buffer.
    {
        lastSaveData.assign(data);
    }

    if (data[0] == '\0')
    {
        ASSERT(!instance->GetEluna()->HasInstanceData(instance));

        // Create a new table for instance data.
        lua_State* L = instance->GetEluna()->L;
        lua_newtable(L);
        instance->GetEluna()->CreateInstanceData(instance);

        instance->GetEluna()->OnLoad(this);
        // Stack: (empty)
        return;
    }

    size_t decodedLength;
    const unsigned char* decodedData = ElunaUtil::DecodeData(data, &decodedLength);
    lua_State* L = instance->GetEluna()->L;

    if (decodedData)
    {
        // Stack: (empty)

        lua_pushcfunction(L, mar_decode);
        lua_pushlstring(L, (const char*)decodedData, decodedLength);
        // Stack: mar_decode, decoded_data

        // Call `mar_decode` and check for success.
        if (lua_pcall(L, 1, 1, 0) == 0)
        {
            // Stack: data
            // Only use the data if it's a table.
            if (lua_istable(L, -1))
            {
                instance->GetEluna()->CreateInstanceData(instance);
                // Stack: (empty)
                instance->GetEluna()->OnLoad(this);
                // WARNING! lastSaveData might be different after `OnLoad` if the Lua code saved data.
            }
            else
            {
                ELUNA_LOG_ERROR("Error while loading instance data: Expected data to be a table (type 5), got type %d instead", lua_type(L, -1));
                lua_pop(L, 1);
                // Stack: (empty)

                Initialize();
            }
        }
        else
        {
            // Stack: error_message
            ELUNA_LOG_ERROR("Error while parsing instance data with lua-marshal: %s", lua_tostring(L, -1));
            lua_pop(L, 1);
            // Stack: (empty)

            Initialize();
        }

        delete[] decodedData;
    }
    else
    {
        ELUNA_LOG_ERROR("Error while decoding instance data: Data is not valid base-64");
        Initialize();
    }
}
Пример #9
0
// 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);

    // Create hidden table with weak values
    lua_newtable(sEluna->L);
    lua_newtable(sEluna->L);
    lua_pushstring(sEluna->L, "v");
    lua_setfield(sEluna->L, -2, "__mode");
    lua_setmetatable(sEluna->L, -2);
    sHookMgr->userdata_table = luaL_ref(sEluna->L, LUA_REGISTRYINDEX);

    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<Creature>::ReadGuard g(HashMapHolder<Creature>::GetLock());
    HashMapHolder<Creature>::MapType& m = HashMapHolder<Creature>::GetContainer();
    for (HashMapHolder<Creature>::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<GameObject>::ReadGuard g(HashMapHolder<GameObject>::GetLock());
    HashMapHolder<GameObject>::MapType& m = HashMapHolder<GameObject>::GetContainer();
    for (HashMapHolder<GameObject>::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;
}
Пример #10
0
void Eluna::Report(lua_State* _L)
{
    const char* msg = lua_tostring(_L, -1);
    ELUNA_LOG_ERROR("%s", msg);
    lua_pop(_L, 1);
}
Пример #11
0
void Eluna::RunScripts()
{
    LOCK_ELUNA;
    if (!IsEnabled())
        return;

    uint32 oldMSTime = ElunaUtil::GetCurrTime();
    uint32 count = 0;

    ScriptList scripts;
    lua_extensions.sort(ScriptPathComparator);
    lua_scripts.sort(ScriptPathComparator);
    scripts.insert(scripts.end(), lua_extensions.begin(), lua_extensions.end());
    scripts.insert(scripts.end(), lua_scripts.begin(), lua_scripts.end());

    std::unordered_map<std::string, std::string> loaded; // filename, path

    lua_getglobal(L, "package");
    // Stack: package
    luaL_getsubtable(L, -1, "loaded");
    // Stack: package, modules
    int modules = lua_gettop(L);
    for (ScriptList::const_iterator it = scripts.begin(); it != scripts.end(); ++it)
    {
        // Check that no duplicate names exist
        if (loaded.find(it->filename) != loaded.end())
        {
            ELUNA_LOG_ERROR("[Eluna]: Error loading `%s`. File with same name already loaded from `%s`, rename either file", it->filepath.c_str(), loaded[it->filename].c_str());
            continue;
        }
        loaded[it->filename] = it->filepath;

        lua_getfield(L, modules, it->filename.c_str());
        // Stack: package, modules, module
        if (!lua_isnoneornil(L, -1))
        {
            lua_pop(L, 1);
            ELUNA_LOG_DEBUG("[Eluna]: `%s` was already loaded or required", it->filepath.c_str());
            continue;
        }
        lua_pop(L, 1);
        // Stack: package, modules

        if (luaL_loadfile(L, it->filepath.c_str()))
        {
            // Stack: package, modules, errmsg
            ELUNA_LOG_ERROR("[Eluna]: Error loading `%s`", it->filepath.c_str());
            Report(L);
            // Stack: package, modules
            continue;
        }
        // Stack: package, modules, filefunc

        if (ExecuteCall(0, 1))
        {
            // Stack: package, modules, result
            if (lua_isnoneornil(L, -1) || (lua_isboolean(L, -1) && !lua_toboolean(L, -1)))
            {
                // if result evaluates to false, change it to true
                lua_pop(L, 1);
                Push(L, true);
            }
            lua_setfield(L, modules, it->filename.c_str());
            // Stack: package, modules

            // successfully loaded and ran file
            ELUNA_LOG_DEBUG("[Eluna]: Successfully loaded `%s`", it->filepath.c_str());
            ++count;
            continue;
        }
    }
    // Stack: package, modules
    lua_pop(L, 2);
    ELUNA_LOG_INFO("[Eluna]: Executed %u Lua scripts in %u ms", count, ElunaUtil::GetTimeDiff(oldMSTime));

    OnLuaStateOpen();
}