/** * @brief Executes the Lua script from bytecode. * * @param pUser The user running the script. * @param pNpc The NPC attached to the script. * @param nEventID Identifier for the event. * @param bSelectedReward The reward selected, if applicable. * @param filename The script's filename for debugging purposes. * @param bytecode The script's compiled bytecode. * * @return true if it succeeds, false if it fails. */ bool CLuaScript::ExecuteScript(CUser * pUser, CNpc * pNpc, int32 nEventID, int8 bSelectedReward, const char * filename, BytecodeBuffer & bytecode) { // Ensure that we wait until the last user's done executing their script. FastGuard lock(m_lock); /* Attempt to run the script. */ // Load the buffer with our bytecode. int err = luaL_loadbuffer(m_luaState, reinterpret_cast<const char *>(&bytecode[0]), bytecode.size(), nullptr); if (err != LUA_OK) { RetrieveLoadError(err, filename); return false; } #if !defined(USE_ORIGINAL_QUESTS) // our quest implementation // The user & NPC instances are globals. As is the selected quest reward. lua_tsetglobal(m_luaState, LUA_SCRIPT_GLOBAL_USER, pUser); lua_tsetglobal(m_luaState, LUA_SCRIPT_GLOBAL_NPC, pNpc); lua_tsetglobal(m_luaState, LUA_SCRIPT_GLOBAL_SELECTED_REWARD, bSelectedReward); // Find & assign script's entry point to the stack lua_getglobal(m_luaState, LUA_SCRIPT_ENTRY_POINT); // Entry point requires 1 arguments: the event ID. lua_tpush(m_luaState, nEventID); // Try calling the script's entry point (Main()). err = lua_pcall(m_luaState, 1, // 1 arguments 0, // 0 returned values 0); // no error handler #else lua_tsetglobal(m_luaState, "UID", pUser->GetID()); lua_tsetglobal(m_luaState, "STEP", bSelectedReward); lua_tsetglobal(m_luaState, "EVENT", nEventID); // Try calling the script's entry point err = lua_pcall(m_luaState, 0, // no arguments 0, // 0 returned values 0); // no error handler #endif // Nothing returned, so we can finish up here. if (err == LUA_OK) { #if defined(USE_ORIGINAL_QUESTS) lua_settop(m_luaState, 0); #endif return true; } // Attempt to provide somewhat informative errors to help the user figure out what's wrong. switch (err) { case LUA_ERRRUN: printf("ERROR: A runtime error occurred within Lua script `%s`.\n", filename); break; case LUA_ERRMEM: printf("ERROR: Unable to allocate memory during execution of Lua script `%s`.\n", filename); break; case LUA_ERRERR: printf("ERROR: An error occurred during Lua script `%s`. Error handler failed.\n", filename); break; default: printf("ERROR: An unknown error occurred in Lua script `%s`.\n", filename); break; } // Is there an error set? That can be more useful than our generic error. if (lua_isstring(m_luaState, -1)) { printf("ERROR: [%s] The following error was provided:\n%s\n", filename, lua_to<const char *>(m_luaState, -1)); } #if defined(USE_ORIGINAL_QUESTS) lua_settop(m_luaState, 0); #endif return false; }
/** * @brief Executes the Lua script from bytecode. * * @param pUser The user running the script. * @param pNpc The NPC attached to the script. * @param nEventID Identifier for the event. * @param bSelectedReward The reward selected, if applicable. * @param filename The script's filename for debugging purposes. * @param bytecode The script's compiled bytecode. * * @return true if it succeeds, false if it fails. */ bool CLuaScript::ExecuteScript(CUser * pUser, CNpc * pNpc, int32 nEventID, int8 bSelectedReward, const char * filename, BytecodeBuffer & bytecode) { // Ensure that we wait until the last user's done executing their script. Guard lock(m_lock); /* Attempt to run the script. */ // Load the buffer with our bytecode. int err = luaL_loadbuffer(m_luaState, reinterpret_cast<const char *>(&bytecode[0]), bytecode.size(), nullptr); if (err != LUA_OK) { RetrieveLoadError(err, filename); return false; } lua_tsetglobal(m_luaState, "UID", pUser->GetID()); lua_tsetglobal(m_luaState, "STEP", bSelectedReward); lua_tsetglobal(m_luaState, "EVENT", nEventID); // Try calling the script's entry point err = lua_pcall(m_luaState, 0, // no arguments 0, // 0 returned values 0); // no error handler // Nothing returned, so we can finish up here. if (err == LUA_OK) { lua_settop(m_luaState, 0); return true; } // Attempt to provide somewhat informative errors to help the user figure out what's wrong. switch (err) { case LUA_ERRRUN: printf("ERROR: A runtime error occurred within Lua script.\n"); printf("FILE: %s\n", filename); printf("USER: %s\n", pUser->GetName().c_str()); printf("ZONE: %d\n", pUser->GetZoneID()); printf("NPC ID: %d\n", pNpc->m_sSid); printf("-\n"); break; case LUA_ERRMEM: printf("ERROR: Unable to allocate memory during execution of Lua script.\n"); printf("FILE: %s\n", filename); printf("USER: %s\n", pUser->GetName().c_str()); printf("ZONE: %d\n", pUser->GetZoneID()); printf("NPC ID: %d\n", pNpc->m_sSid); printf("-\n"); break; case LUA_ERRERR: printf("ERROR: An error occurred during Lua script, Error handler failed.\n"); printf("FILE: %s\n", filename); printf("USER: %s\n", pUser->GetName().c_str()); printf("ZONE: %d\n", pUser->GetZoneID()); printf("NPC ID: %d\n", pNpc->m_sSid); printf("-\n"); break; default: printf("ERROR: An unknown error occurred in Lua script.\n"); printf("FILE: %s\n", filename); printf("USER: %s\n", pUser->GetName().c_str()); printf("ZONE: %d\n", pUser->GetZoneID()); printf("NPC ID: %d\n", pNpc->m_sSid); printf("-\n"); break; } // Is there an error set? That can be more useful than our generic error. if (lua_isstring(m_luaState, -1)) { printf("ERROR: [%s] The following error was provided.\n",filename); printf("MESSAGE: %s\n", lua_to<const char *>(m_luaState, -1)); printf("-\n"); } lua_settop(m_luaState, 0); return false; }